Java tutorial
/* * ================================================================================================= * Copyright (C) 2015 Martin Albedinsky * ================================================================================================= * Licensed under the Apache License, Version 2.0 or later (further "License" only). * ------------------------------------------------------------------------------------------------- * You may use this file only in compliance with the License. More details and copy of this License * you may obtain at * * http://www.apache.org/licenses/LICENSE-2.0 * * You can redistribute, modify or publish any part of the code written within this file but as it * is described in the License, the software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY KIND. * * See the License for the specific language governing permissions and limitations under the License. * ================================================================================================= */ package com.albedinsky.android.ui.navigation; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import com.albedinsky.android.ui.R; import java.util.LinkedList; /** * A {@link DrawerLayout} implementation designed to present set of {@link NavigationItem NavigationItems} * within a simple navigation list. The navigation list is contained within navigation drawer at the * start (left) position of NavigationLayout. * <p> * Set of navigation items can be provided through {@link BaseNavigationAdapter} implementation that * can be set via {@link #setNavigationAdapter(ListAdapter)}. The navigation layout will automatically * handle all clicks on item views provided by such adapter and also theirs proper selection. The * navigation item click events will be dispatched through {@link OnNavigationItemClickListener} * listener that can be registered via {@link #setOnNavigationItemClickListener(OnNavigationItemClickListener)}. * <p> * The NavigationLayout also by default creates an instance of {@link NavigationHeaderView} and inserts * it into the navigation list as its header view. The current navigation header view can be obtained * via {@link #getNavigationHeaderView()}. Custom header view can be specified via {@link #setNavigationHeaderView(View)} * and removed via {@link #removeNavigationHeaderView()}. See {@link NavigationHeaderView} for provided * API allowing to bind such view with desired information. * <p> * If needed opened navigation drawer can be closed via {@link #closeNavigation()} or opened via * {@link #openNavigation()}. * * <h3>Navigation item click handling</h3> * As described above, the navigation layout will dispatch all navigation item click events to registered * OnNavigationItemClickListener via * {@link OnNavigationItemClickListener#onNavigationItemClick(NavigationLayout, View, NavigationItem, int) onNavigationItemClick(NavigationLayout, View, NavigationItem, int)}. * It is a good practice to schedule execution of action associated with the clicked navigation item * until the navigation drawer is closed. You can do so via {@link #scheduleNavigationAction(Runnable)} * where such Runnable action will be executed after the navigation drawer is closed. * * <h3>Styling</h3> * <b>Directly</b> * <ul> * <li>{@link R.attr#uiNavigationDrawerShadow uiNavigationDrawerShadow}</li> * <li>{@link R.attr#uiColorScrim uiColorScrim}</li> * </ul> * <p> * <b>Via Theme</b> * <ul> * <li>{@link R.attr#uiNavigationLayoutStyle uiNavigationLayoutStyle}</li> * <li>{@link R.attr#uiNavigationWidth uiNavigationWidth}</li> * <li>{@link R.attr#uiNavigationBackground uiNavigationBackground}</li> * <li>{@link R.attr#uiNavigationDivider uiNavigationDivider}</li> * <li>{@link R.attr#uiNavigationListSelector uiNavigationListSelector}</li> * <li>{@link R.attr#uiNavigationListViewStyle uiNavigationListViewStyle}</li> * <li>{@link R.attr#uiNavigationSubheaderStyle uiNavigationSubheaderStyle}</li> * <li>{@link R.attr#uiNavigationToolbarLayout uiNavigationToolbarLayout}</li> * </ul> * * @author Martin Albedinsky */ public class NavigationLayout extends DrawerLayout implements AdapterView.OnItemClickListener { /** * Interface =================================================================================== */ /** * Listener that can receive callbacks about <b>opened</b> and <b>closed</b> navigation. * * @author Martin Albedinsky */ public interface OnNavigationListener { /** * Invoked whenever the navigation drawer has been opened. * * @param navigationLayout Navigation layout in which has been the drawer opened. */ void onNavigationOpened(@NonNull NavigationLayout navigationLayout); /** * Invoked whenever the navigation drawer has been closed. * * @param navigationLayout Navigation layout in which has been the drawer closed. */ void onNavigationClosed(@NonNull NavigationLayout navigationLayout); } /** * Listener that can receive callbacks about clicked navigation item or clicked navigation header. * * @author Martin Albedinsky */ public interface OnNavigationItemClickListener { /** * Invoked whenever the specified <var>headerView</var> has been clicked within the given * <var>navigationLayout</var>. * * @param navigationLayout The navigation layout containing the clicked header view. * @param headerView The clicked header view. */ void onNavigationHeaderClick(@NonNull NavigationLayout navigationLayout, @NonNull View headerView); /** * Invoked whenever the specified <var>itemView</var> has been clicked within the given * <var>navigationLayout</var>. * * @param navigationLayout The navigation layout containing the clicked item view. * @param itemView The clicked item view. * @param item Navigation item that is associated with the clicked view. * @param position Position of the navigation item within the current data set of * attached navigation adapter. */ void onNavigationItemClick(@NonNull NavigationLayout navigationLayout, @NonNull View itemView, @NonNull NavigationItem item, int position); } /** * Constants =================================================================================== */ /** * Log TAG. */ // private static final String TAG = "NavigationLayout"; /** * Gravity of the drawer containing navigation items. */ public static final int NAVIGATION_DRAWER_GRAVITY = Gravity.LEFT | Gravity.START; /** * Static members ============================================================================== */ /** * Members ===================================================================================== */ /** * Queue of navigation actions waiting to run. */ private LinkedList<Runnable> mWaitingActions; /** * Registered navigation listener (if any). */ private OnNavigationListener mListener; /** * List view used to present data set of attached navigation adapter. */ private ListView mNavigationListView; /** * Adapter with data set containing navigation items to be presented within {@link #mNavigationListView}. */ private BaseNavigationAdapter mNavigationAdapter; /** * Registered navigation item click listener (if any). */ private OnNavigationItemClickListener mItemClickListener; /** * Action bar toggle used to handle toggling between navigation drawer's opened and closed state. */ private ActionBarDrawerToggle mActionBarToggle; /** * Current header view presented within navigation list view (if any). */ private View mHeaderView; /** * Current spacer presented within navigation list view (if any). */ private View mHeaderViewSpacer; /** * Inflater used to inflate custom views for this navigation layout. */ private LayoutInflater mLayoutInflater; /** * Constructors ================================================================================ */ /** * Same as {@link #NavigationLayout(android.content.Context, android.util.AttributeSet)} without * attributes. */ public NavigationLayout(Context context) { this(context, null); } /** * Same as {@link #NavigationLayout(android.content.Context, android.util.AttributeSet, int)} * with {@link R.attr#uiNavigationLayoutStyle} as attribute for default style. */ public NavigationLayout(Context context, AttributeSet attrs) { this(context, attrs, R.attr.uiNavigationLayoutStyle); } /** * Same as {@link #NavigationLayout(android.content.Context, android.util.AttributeSet, int, int)} * with {@code 0} as default style. */ public NavigationLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.init(context, attrs, defStyleAttr, 0); } /** * Creates a new instance of NavigationLayout within the given <var>context</var>. * * @param context Context in which will be the new view presented. * @param attrs Set of Xml attributes used to configure the new instance of this view. * @param defStyleAttr An attribute which contains a reference to a default style resource for * this view within a theme of the given context. * @param defStyleRes Resource id of the default style for the new view. */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) public NavigationLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr); this.init(context, attrs, defStyleAttr, defStyleRes); } /** * Methods ===================================================================================== */ /** * Called from one of constructors of this view to perform its initialization. * <p> * Initialization is done via parsing of the specified <var>attrs</var> set and obtaining for * this view specific data from it that can be used to configure this new view instance. The * specified <var>defStyleAttr</var> and <var>defStyleRes</var> are used to obtain default data * from the current theme provided by the specified <var>context</var>. */ @SuppressWarnings("ResourceType") private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { mLayoutInflater = LayoutInflater.from(context); int initialLayout = 0; /** * Process attributes. */ final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Ui_NavigationLayout, defStyleAttr, defStyleRes); if (typedArray != null) { final int n = typedArray.getIndexCount(); for (int i = 0; i < n; i++) { int index = typedArray.getIndex(i); if (index == R.styleable.Ui_NavigationLayout_android_initialLayout) { initialLayout = typedArray.getResourceId(index, initialLayout); } else if (index == R.styleable.Ui_NavigationLayout_uiNavigationDrawerShadow) { final int resId = typedArray.getResourceId(index, -1); if (resId != -1) setDrawerShadow(resId, NAVIGATION_DRAWER_GRAVITY); } else if (index == R.styleable.Ui_NavigationLayout_uiColorScrim) { setScrimColor(typedArray.getColor(index, Color.TRANSPARENT)); } } typedArray.recycle(); } if (initialLayout != 0) { mLayoutInflater.inflate(initialLayout, this); this.handleInflationFinished(); } } /** */ @Override protected void onFinishInflate() { super.onFinishInflate(); this.handleInflationFinished(); } /** * Called after inflation of view hierarchy of this layout has been finished. */ private void handleInflationFinished() { final ListView listView = (ListView) findViewById(R.id.ui_navigation_list_view); if (listView != mNavigationListView) { this.mNavigationListView = listView; this.ensureHeaderViewWithinNavigationList(); if (mNavigationListView != null) mNavigationListView.setOnItemClickListener(this); } this.ensureToolbarWithinLayout(); } /** * Ensures that a header view is presented within the current navigation list. If not the default * {@link NavigationHeaderView} will be inflated and inserted. */ private void ensureHeaderViewWithinNavigationList() { if (mNavigationListView != null) { final View headerView = mLayoutInflater.inflate(R.layout.ui_header_navigation, mNavigationListView, false); setNavigationHeaderView(headerView); } } /** * Ensures that a toolbar widget is contained within the current view hierarchy of this navigation * layout. If not it will be inflated from a layout resource presented within the current theme * and inserted into this layout at the proper place. */ private void ensureToolbarWithinLayout() { final View toolbar = findViewById(R.id.ui_toolbar); if (toolbar == null) { final ViewGroup contentLayout = (ViewGroup) findViewById(R.id.ui_navigation_layout_content); if (contentLayout != null) { final Context context = getContext(); final TypedValue typedValue = new TypedValue(); if (context.getTheme().resolveAttribute(R.attr.uiNavigationToolbarLayout, typedValue, true)) { // Insert the Toolbar above the content container. contentLayout.addView(mLayoutInflater.inflate(typedValue.resourceId, contentLayout, false), 0); } } } } /** * Like {@link #createActionBarToggle(Activity, int, int)} where the created toggle will be attached * to this navigation layout if it is not attached yet. */ public void createAndAttachActionBarToggle(@NonNull Activity activity, @StringRes int openDrawerContentDescRes, @StringRes int closeDrawerContentDescRes) { if (mActionBarToggle == null) { this.mActionBarToggle = createActionBarToggle(activity, openDrawerContentDescRes, closeDrawerContentDescRes); setDrawerListener(mActionBarToggle); } } /** * Creates a new instance of ActionBarDrawerToggle for the specified <var>activity</var>. The * created toggle is also used by this navigation layout to properly close/open its navigation * drawer. * * @param activity The activity for which to create the toggle. * @param openDrawerContentDescRes Resource id of content description text for the open navigation * drawer action. * @param closeDrawerContentDescRes Resource id of content description text for the close navigation * drawer action. * @return New instance of ActionBarDrawerToggle. */ @NonNull public ActionBarDrawerToggle createActionBarToggle(@NonNull Activity activity, @StringRes int openDrawerContentDescRes, @StringRes int closeDrawerContentDescRes) { this.attachActivityAsListener(activity); return new ActionBarToggle(activity, this, openDrawerContentDescRes, closeDrawerContentDescRes); } /** * Attaches the specified <var>activity</var> as one of {@link OnNavigationListener} or {@link OnNavigationItemClickListener} * if they are implemented by the activity. * * @param activity The activity to be attached as listener to this navigation layout. */ private void attachActivityAsListener(Activity activity) { if (activity instanceof OnNavigationListener) { setOnNavigationListener((OnNavigationListener) activity); } if (activity instanceof OnNavigationItemClickListener) { setOnNavigationItemClickListener((OnNavigationItemClickListener) activity); } } /** * If attached to action bar toggle via {@link #createAndAttachActionBarToggle(Activity, int, int)} * this will return that toggle. * * @return Current attached toggle or {@code null} if no toggle has been created and attached yet. */ @Nullable public ActionBarDrawerToggle getActionBarToggle() { return mActionBarToggle; } /** * If attached to action bar toggle via {@link #createAndAttachActionBarToggle(Activity, int, int)} * this will delegate {@link ActionBarDrawerToggle#onConfigurationChanged(Configuration)} to that * toggle. * <p> * This should be called whenever {@link Activity#onConfigurationChanged(Configuration)} is invoked. * * @param newConfig The new configuration to be delegated to the attached action bar toggle. */ public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { if (mActionBarToggle != null) mActionBarToggle.onConfigurationChanged(newConfig); } /** * If attached to action bar toggle via {@link #createAndAttachActionBarToggle(Activity, int, int)} * this will delegate {@link ActionBarDrawerToggle#onOptionsItemSelected(MenuItem)} to that toggle. * <p> * This should be called whenever {@link Activity#onOptionsItemSelected(MenuItem)} is invoked. * * @param item The selected menu item to be delegated to the attached action bar toggle. * @return {@code True} if the toggle has processed the specified item's selection, {@code false} * otherwise. */ public boolean dispatchOptionsItemSelected(@NonNull MenuItem item) { return mActionBarToggle != null && mActionBarToggle.onOptionsItemSelected(item); } /** * If attached to action bar toggle via {@link #createAndAttachActionBarToggle(Activity, int, int)} * this will delegate {@link ActionBarDrawerToggle#syncState()} to that toggle. * <p> * This should be called whenever {@link Activity#onPostCreate(Bundle)} is invoked. */ public void syncState() { if (mActionBarToggle != null) mActionBarToggle.syncState(); } /** * Specifies a view that should be inserted into navigation list as header view. * <p> * The current header view (if any) will be removed. * * @param headerView The desired header view. * @see #getNavigationHeaderView() */ public void setNavigationHeaderView(@NonNull View headerView) { if (mNavigationListView != null) { removeNavigationHeaderView(); this.mHeaderView = headerView; mNavigationListView.addHeaderView(headerView, null, true); this.mHeaderViewSpacer = mLayoutInflater.inflate(R.layout.ui_spacer_navigation, mNavigationListView, false); mNavigationListView.addHeaderView(mHeaderViewSpacer, null, false); } } /** * Returns the current header view presented within the navigation list. * <p> * This navigation layout creates by default an instance of {@link NavigationHeaderView} that is * inserted into navigation list so if it has not been removed it will be returned here. * * @return Current header view or {@code null} if header view has been removed or not specified. */ @Nullable public View getNavigationHeaderView() { return mHeaderView; } /** * Removes the current header view from the navigation list. * * @return {@code True} if header view has been removed, {@code false} if there was no header to * be removed or not navigation list from to which to remove the header. */ public boolean removeNavigationHeaderView() { if (mNavigationListView != null) { if (mHeaderView != null) { mNavigationListView.removeHeaderView(mHeaderView); mNavigationListView.removeHeaderView(mHeaderViewSpacer); this.mHeaderViewSpacer = null; this.mHeaderView = null; return true; } } return false; } /** * Sets an adapter that provides data set of navigation items for the navigation list that is * presented within navigation drawer. * * @param adapter The desired adapter. * @see #getNavigationAdapter() */ public void setNavigationAdapter(@NonNull ListAdapter adapter) { if (adapter instanceof BaseNavigationAdapter) { this.mNavigationAdapter = (BaseNavigationAdapter) adapter; } else { this.mNavigationAdapter = null; } if (mNavigationListView != null) { mNavigationListView.setAdapter(adapter); } } /** * Returns the current attached navigation adapter. * * @see #setNavigationAdapter(ListAdapter) */ @Nullable public ListAdapter getNavigationAdapter() { return mNavigationListView != null ? mNavigationListView.getAdapter() : null; } /** * Registers a callback to be invoked whenever a navigation drawer is opened or closed. * * @param listener Listener callback. * @see #removeOnNavigationListener() */ public void setOnNavigationListener(@NonNull OnNavigationListener listener) { this.mListener = listener; } /** * Removes the current OnNavigationListener callback (if any). */ public void removeOnNavigationListener() { this.mListener = null; } /** * Registers a callback to be invoked whenever a navigation item or navigation header are clicked. * * @param listener Listener callback. * @see #removeOnNavigationItemClickListener() */ public void setOnNavigationItemClickListener(@NonNull OnNavigationItemClickListener listener) { this.mItemClickListener = listener; } /** * Removes the current OnNavigationItemClickListener callback (if any). */ public void removeOnNavigationItemClickListener() { this.mItemClickListener = null; } /** */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // There are two headers in navigation list view. final int itemPosition = position - 2; if (position == 0) { this.notifyNavigationHeaderClick(mHeaderView); } else if (itemPosition != getSelectedNavigationItemPosition()) { this.setNavigationItemSelected(itemPosition); this.notifyNavigationItemClick(view, itemPosition); } else { closeNavigation(); } } /** * Returns a position of the navigation item that is at this time selected. * * @return Selected navigation item position. * @see BaseNavigationAdapter#getSelectedItemPosition() */ public int getSelectedNavigationItemPosition() { return mNavigationAdapter != null ? mNavigationAdapter.getSelectedItemPosition() : -1; } /** * Sets selected navigation item at the specified <var>position</var>. * * @param position Position of the desired navigation item to be selected. * @return {@code True} if current selected item has been changed, {@code false} otherwise. * @see BaseNavigationAdapter#setItemSelected(int) */ public boolean setNavigationItemSelected(int position) { return mNavigationAdapter != null && mNavigationAdapter.setItemSelected(position); } /** * Notifies current OnNavigationItemClickListener (if any) that the specified <var>headerView</var> * has been clicked. * * @param headerView The clicked header view. */ @SuppressWarnings("ConstantConditions") private void notifyNavigationHeaderClick(View headerView) { if (mItemClickListener != null) mItemClickListener.onNavigationHeaderClick(this, headerView); } /** * Notifies current OnNavigationItemClickListener (if any) that the specified <var>itemView</var> * at the given position has been clicked. * * @param itemView The clicked item view. * @param position Position of navigation item associated with the clicked item view within data * set of attached navigation adapter. */ @SuppressWarnings("ConstantConditions") private void notifyNavigationItemClick(View itemView, int position) { if (mNavigationAdapter != null && mItemClickListener != null) { mItemClickListener.onNavigationItemClick(this, itemView, mNavigationAdapter.getItem(position), position); } } /** * Toggles the current state (open/closed) of the navigation. If the navigation is open this will * close it, otherwise it will open it. * * @return {@code True} if the navigation has been opened, {@code false} otherwise. */ public boolean toggleNavigation() { if (isNavigationOpen()) { closeNavigation(); return false; } openNavigation(); return true; } /** * Returns a flag indicating whether the navigation is open or not. * * @return {@code True} if the navigation is open so it is visible to a user, {@code false} otherwise. */ @SuppressWarnings("ResourceType") public boolean isNavigationOpen() { return isDrawerOpen(NAVIGATION_DRAWER_GRAVITY); } /** * Closes the navigation so a user can no longer interact with its items, if it is currently open. * * @return {@code True} if the navigation has been closed, {@code false} if it hasn't because it * was already closed. */ @SuppressWarnings("ResourceType") public boolean closeNavigation() { if (isNavigationOpen()) { closeDrawer(NAVIGATION_DRAWER_GRAVITY); return true; } return false; } /** * Opens the navigation so it will be visible to a user, if it is currently closed. * * @return {@code True} if the navigation has been opened, {@code false} if it hasn't because it * was already open. */ @SuppressWarnings("ResourceType") public boolean openNavigation() { if (!isNavigationOpen()) { openDrawer(NAVIGATION_DRAWER_GRAVITY); return true; } return false; } /** * Invoked whenever the navigation has been opened within this navigation layout so it is * currently visible to a user. */ protected void onNavigationOpened() { this.notifyNavigationOpened(); } /** * Notifies the current OnNavigationListener (if any) that the navigation has been opened. */ private void notifyNavigationOpened() { if (mListener != null) mListener.onNavigationOpened(this); } /** * Invoked whenever the navigation has been closed within this navigation layout so a user * cannot to interact with it. * <p> * This implementation will run all waiting navigation actions via {@link #runAllWaitingNavigationActions()} * (if any). */ protected void onNavigationClosed() { if (hasWaitingNavigationActions()) { runAllWaitingNavigationActions(); } this.notifyNavigationClosed(); } /** * Notifies the current OnNavigationListener (if any) that the navigation has been closed. */ private void notifyNavigationClosed() { if (mListener != null) mListener.onNavigationClosed(this); } /** * Like {@link #registerNavigationAction(Runnable)}, but this will register the specified action * if the navigation drawer is open and will close the navigation drawer to run the specified action, * otherwise will run the specified action immediately. * * @see #isNavigationOpen() */ public final void scheduleNavigationAction(@NonNull Runnable action) { if (isNavigationOpen()) { registerNavigationAction(action); closeNavigation(); } else { action.run(); } } /** * Inserts the given action into the currently waiting navigation actions. * * @param action Action to be registered. * @see #runTopWaitingNavigationAction() * @see #runAllWaitingNavigationActions() */ public final void registerNavigationAction(@NonNull Runnable action) { if (mWaitingActions == null) { this.mWaitingActions = new LinkedList<>(); } mWaitingActions.add(action); } /** * Returns a flag indicating whether there are some waiting navigation actions to be run at this * time or not. * * @return {@code True} if there are some waiting actions, {@code false} otherwise. * @see #runTopWaitingNavigationAction() * @see #runAllWaitingNavigationActions() */ public final boolean hasWaitingNavigationActions() { return mWaitingActions != null && !mWaitingActions.isEmpty(); } /** * Runs the top waiting navigation action (if any). * * @see #registerNavigationAction(Runnable) */ public final void runTopWaitingNavigationAction() { if (hasWaitingNavigationActions()) mWaitingActions.poll().run(); } /** * Runs all waiting navigation actions (if any). * * @see #registerNavigationAction(Runnable) */ public final void runAllWaitingNavigationActions() { if (hasWaitingNavigationActions()) { while (!mWaitingActions.isEmpty()) { mWaitingActions.poll().run(); } } } /** */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return isEnabled() && super.onInterceptTouchEvent(ev); } /** */ @Override public boolean onTouchEvent(MotionEvent ev) { return isEnabled() && super.onTouchEvent(ev); } /** * Inner classes =============================================================================== */ /** * Helper implementation of {@link android.support.v7.app.ActionBarDrawerToggle} that can be used * to toggle visibility (open, closed) of the navigation slider of this navigation layout. */ private final class ActionBarToggle extends ActionBarDrawerToggle { /** * Creates a new instance of ActionBarToggle helper for the specified <var>activity</var> and * <var>drawerLayout</var>. * * @param activity The activity that has the drawer layout presented within * its view hierarchy. * @param drawerLayout Drawer layout that should be managed by the new toolbar * toggle helper. * @param openDrawerContentDescRes Resource id of description text for open drawer action. * @param closeDrawerContentDescRes Resource if of description text for close drawer action. */ ActionBarToggle(Activity activity, DrawerLayout drawerLayout, int openDrawerContentDescRes, int closeDrawerContentDescRes) { super(activity, drawerLayout, openDrawerContentDescRes, closeDrawerContentDescRes); } /** */ @Override public void onDrawerClosed(View drawerView) { onNavigationClosed(); } /** */ @Override public void onDrawerOpened(View drawerView) { onNavigationOpened(); } } }