1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.support.v7.app;
17
18import android.app.ActionBar;
19import android.app.Activity;
20import android.content.Context;
21import android.content.res.Configuration;
22import android.content.res.TypedArray;
23import android.graphics.drawable.Drawable;
24import android.os.Build;
25import android.support.annotation.NonNull;
26import android.support.annotation.Nullable;
27import android.support.annotation.StringRes;
28import android.support.v4.view.GravityCompat;
29import android.support.v4.widget.DrawerLayout;
30import android.support.v7.graphics.drawable.DrawerArrowDrawable;
31import android.support.v7.widget.Toolbar;
32import android.util.Log;
33import android.view.MenuItem;
34import android.view.View;
35
36/**
37 * This class provides a handy way to tie together the functionality of
38 * {@link android.support.v4.widget.DrawerLayout} and the framework <code>ActionBar</code> to
39 * implement the recommended design for navigation drawers.
40 *
41 * <p>To use <code>ActionBarDrawerToggle</code>, create one in your Activity and call through
42 * to the following methods corresponding to your Activity callbacks:</p>
43 *
44 * <ul>
45 * <li>{@link android.app.Activity#onConfigurationChanged(android.content.res.Configuration)
46 * onConfigurationChanged}
47 * <li>{@link android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
48 * onOptionsItemSelected}</li>
49 * </ul>
50 *
51 * <p>Call {@link #syncState()} from your <code>Activity</code>'s
52 * {@link android.app.Activity#onPostCreate(android.os.Bundle) onPostCreate} to synchronize the
53 * indicator with the state of the linked DrawerLayout after <code>onRestoreInstanceState</code>
54 * has occurred.</p>
55 *
56 * <p><code>ActionBarDrawerToggle</code> can be used directly as a
57 * {@link android.support.v4.widget.DrawerLayout.DrawerListener}, or if you are already providing
58 * your own listener, call through to each of the listener methods from your own.</p>
59 *
60 * <p>
61 * You can customize the the animated toggle by defining the
62 * {@link android.support.v7.appcompat.R.styleable#DrawerArrowToggle drawerArrowStyle} in your
63 * ActionBar theme.
64 */
65public class ActionBarDrawerToggle implements DrawerLayout.DrawerListener {
66
67    /**
68     * Allows an implementing Activity to return an {@link ActionBarDrawerToggle.Delegate} to use
69     * with ActionBarDrawerToggle.
70     */
71    public interface DelegateProvider {
72
73        /**
74         * @return Delegate to use for ActionBarDrawableToggles, or null if the Activity
75         * does not wish to override the default behavior.
76         */
77        @Nullable
78        Delegate getDrawerToggleDelegate();
79    }
80
81    public interface Delegate {
82
83        /**
84         * Set the Action Bar's up indicator drawable and content description.
85         *
86         * @param upDrawable     - Drawable to set as up indicator
87         * @param contentDescRes - Content description to set
88         */
89        void setActionBarUpIndicator(Drawable upDrawable, @StringRes int contentDescRes);
90
91        /**
92         * Set the Action Bar's up indicator content description.
93         *
94         * @param contentDescRes - Content description to set
95         */
96        void setActionBarDescription(@StringRes int contentDescRes);
97
98        /**
99         * Returns the drawable to be set as up button when DrawerToggle is disabled
100         */
101        Drawable getThemeUpIndicator();
102
103        /**
104         * Returns the context of ActionBar
105         */
106        Context getActionBarThemedContext();
107
108        /**
109         * Returns whether navigation icon is visible or not.
110         * Used to print warning messages in case developer forgets to set displayHomeAsUp to true
111         */
112        boolean isNavigationVisible();
113    }
114
115    private final Delegate mActivityImpl;
116    private final DrawerLayout mDrawerLayout;
117
118    private DrawerArrowDrawable mSlider;
119    private Drawable mHomeAsUpIndicator;
120    boolean mDrawerIndicatorEnabled = true;
121    private boolean mHasCustomUpIndicator;
122    private final int mOpenDrawerContentDescRes;
123    private final int mCloseDrawerContentDescRes;
124    // used in toolbar mode when DrawerToggle is disabled
125    View.OnClickListener mToolbarNavigationClickListener;
126    // If developer does not set displayHomeAsUp, DrawerToggle won't show up.
127    // DrawerToggle logs a warning if this case is detected
128    private boolean mWarnedForDisplayHomeAsUp = false;
129
130    /**
131     * Construct a new ActionBarDrawerToggle.
132     *
133     * <p>The given {@link Activity} will be linked to the specified {@link DrawerLayout} and
134     * its Actionbar's Up button will be set to a custom drawable.
135     * <p>This drawable shows a Hamburger icon when drawer is closed and an arrow when drawer
136     * is open. It animates between these two states as the drawer opens.</p>
137     *
138     * <p>String resources must be provided to describe the open/close drawer actions for
139     * accessibility services.</p>
140     *
141     * @param activity                  The Activity hosting the drawer. Should have an ActionBar.
142     * @param drawerLayout              The DrawerLayout to link to the given Activity's ActionBar
143     * @param openDrawerContentDescRes  A String resource to describe the "open drawer" action
144     *                                  for accessibility
145     * @param closeDrawerContentDescRes A String resource to describe the "close drawer" action
146     *                                  for accessibility
147     */
148    public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout,
149            @StringRes int openDrawerContentDescRes,
150            @StringRes int closeDrawerContentDescRes) {
151        this(activity, null, drawerLayout, null, openDrawerContentDescRes,
152                closeDrawerContentDescRes);
153    }
154
155    /**
156     * Construct a new ActionBarDrawerToggle with a Toolbar.
157     * <p>
158     * The given {@link Activity} will be linked to the specified {@link DrawerLayout} and
159     * the Toolbar's navigation icon will be set to a custom drawable. Using this constructor
160     * will set Toolbar's navigation click listener to toggle the drawer when it is clicked.
161     * <p>
162     * This drawable shows a Hamburger icon when drawer is closed and an arrow when drawer
163     * is open. It animates between these two states as the drawer opens.
164     * <p>
165     * String resources must be provided to describe the open/close drawer actions for
166     * accessibility services.
167     * <p>
168     * Please use {@link #ActionBarDrawerToggle(Activity, DrawerLayout, int, int)} if you are
169     * setting the Toolbar as the ActionBar of your activity.
170     *
171     * @param activity                  The Activity hosting the drawer.
172     * @param toolbar                   The toolbar to use if you have an independent Toolbar.
173     * @param drawerLayout              The DrawerLayout to link to the given Activity's ActionBar
174     * @param openDrawerContentDescRes  A String resource to describe the "open drawer" action
175     *                                  for accessibility
176     * @param closeDrawerContentDescRes A String resource to describe the "close drawer" action
177     *                                  for accessibility
178     */
179    public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout,
180            Toolbar toolbar, @StringRes int openDrawerContentDescRes,
181            @StringRes int closeDrawerContentDescRes) {
182        this(activity, toolbar, drawerLayout, null, openDrawerContentDescRes,
183                closeDrawerContentDescRes);
184    }
185
186    /**
187     * In the future, we can make this constructor public if we want to let developers customize
188     * the
189     * animation.
190     */
191    ActionBarDrawerToggle(Activity activity, Toolbar toolbar, DrawerLayout drawerLayout,
192            DrawerArrowDrawable slider, @StringRes int openDrawerContentDescRes,
193            @StringRes int closeDrawerContentDescRes) {
194        if (toolbar != null) {
195            mActivityImpl = new ToolbarCompatDelegate(toolbar);
196            toolbar.setNavigationOnClickListener(new View.OnClickListener() {
197                @Override
198                public void onClick(View v) {
199                    if (mDrawerIndicatorEnabled) {
200                        toggle();
201                    } else if (mToolbarNavigationClickListener != null) {
202                        mToolbarNavigationClickListener.onClick(v);
203                    }
204                }
205            });
206        } else if (activity instanceof DelegateProvider) { // Allow the Activity to provide an impl
207            mActivityImpl = ((DelegateProvider) activity).getDrawerToggleDelegate();
208        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
209            mActivityImpl = new JellybeanMr2Delegate(activity);
210        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
211            mActivityImpl = new HoneycombDelegate(activity);
212        } else {
213            mActivityImpl = new DummyDelegate(activity);
214        }
215
216        mDrawerLayout = drawerLayout;
217        mOpenDrawerContentDescRes = openDrawerContentDescRes;
218        mCloseDrawerContentDescRes = closeDrawerContentDescRes;
219        if (slider == null) {
220            mSlider = new DrawerArrowDrawable(mActivityImpl.getActionBarThemedContext());
221        } else {
222            mSlider = slider;
223        }
224
225        mHomeAsUpIndicator = getThemeUpIndicator();
226    }
227
228    /**
229     * Synchronize the state of the drawer indicator/affordance with the linked DrawerLayout.
230     *
231     * <p>This should be called from your <code>Activity</code>'s
232     * {@link Activity#onPostCreate(android.os.Bundle) onPostCreate} method to synchronize after
233     * the DrawerLayout's instance state has been restored, and any other time when the state
234     * may have diverged in such a way that the ActionBarDrawerToggle was not notified.
235     * (For example, if you stop forwarding appropriate drawer events for a period of time.)</p>
236     */
237    public void syncState() {
238        if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
239            setPosition(1);
240        } else {
241            setPosition(0);
242        }
243        if (mDrawerIndicatorEnabled) {
244            setActionBarUpIndicator((Drawable) mSlider,
245                    mDrawerLayout.isDrawerOpen(GravityCompat.START) ?
246                            mCloseDrawerContentDescRes : mOpenDrawerContentDescRes);
247        }
248    }
249
250    /**
251     * This method should always be called by your <code>Activity</code>'s
252     * {@link Activity#onConfigurationChanged(android.content.res.Configuration)
253     * onConfigurationChanged}
254     * method.
255     *
256     * @param newConfig The new configuration
257     */
258    public void onConfigurationChanged(Configuration newConfig) {
259        // Reload drawables that can change with configuration
260        if (!mHasCustomUpIndicator) {
261            mHomeAsUpIndicator = getThemeUpIndicator();
262        }
263        syncState();
264    }
265
266    /**
267     * This method should be called by your <code>Activity</code>'s
268     * {@link Activity#onOptionsItemSelected(android.view.MenuItem) onOptionsItemSelected} method.
269     * If it returns true, your <code>onOptionsItemSelected</code> method should return true and
270     * skip further processing.
271     *
272     * @param item the MenuItem instance representing the selected menu item
273     * @return true if the event was handled and further processing should not occur
274     */
275    public boolean onOptionsItemSelected(MenuItem item) {
276        if (item != null && item.getItemId() == android.R.id.home && mDrawerIndicatorEnabled) {
277            toggle();
278            return true;
279        }
280        return false;
281    }
282
283    void toggle() {
284        int drawerLockMode = mDrawerLayout.getDrawerLockMode(GravityCompat.START);
285        if (mDrawerLayout.isDrawerVisible(GravityCompat.START)
286                && (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
287            mDrawerLayout.closeDrawer(GravityCompat.START);
288        } else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
289            mDrawerLayout.openDrawer(GravityCompat.START);
290        }
291    }
292
293    /**
294     * Set the up indicator to display when the drawer indicator is not
295     * enabled.
296     * <p>
297     * If you pass <code>null</code> to this method, the default drawable from
298     * the theme will be used.
299     *
300     * @param indicator A drawable to use for the up indicator, or null to use
301     *                  the theme's default
302     * @see #setDrawerIndicatorEnabled(boolean)
303     */
304    public void setHomeAsUpIndicator(Drawable indicator) {
305        if (indicator == null) {
306            mHomeAsUpIndicator = getThemeUpIndicator();
307            mHasCustomUpIndicator = false;
308        } else {
309            mHomeAsUpIndicator = indicator;
310            mHasCustomUpIndicator = true;
311        }
312
313        if (!mDrawerIndicatorEnabled) {
314            setActionBarUpIndicator(mHomeAsUpIndicator, 0);
315        }
316    }
317
318    /**
319     * Set the up indicator to display when the drawer indicator is not
320     * enabled.
321     * <p>
322     * If you pass 0 to this method, the default drawable from the theme will
323     * be used.
324     *
325     * @param resId Resource ID of a drawable to use for the up indicator, or 0
326     *              to use the theme's default
327     * @see #setDrawerIndicatorEnabled(boolean)
328     */
329    public void setHomeAsUpIndicator(int resId) {
330        Drawable indicator = null;
331        if (resId != 0) {
332            indicator = mDrawerLayout.getResources().getDrawable(resId);
333        }
334        setHomeAsUpIndicator(indicator);
335    }
336
337    /**
338     * @return true if the enhanced drawer indicator is enabled, false otherwise
339     * @see #setDrawerIndicatorEnabled(boolean)
340     */
341    public boolean isDrawerIndicatorEnabled() {
342        return mDrawerIndicatorEnabled;
343    }
344
345    /**
346     * Enable or disable the drawer indicator. The indicator defaults to enabled.
347     *
348     * <p>When the indicator is disabled, the <code>ActionBar</code> will revert to displaying
349     * the home-as-up indicator provided by the <code>Activity</code>'s theme in the
350     * <code>android.R.attr.homeAsUpIndicator</code> attribute instead of the animated
351     * drawer glyph.</p>
352     *
353     * @param enable true to enable, false to disable
354     */
355    public void setDrawerIndicatorEnabled(boolean enable) {
356        if (enable != mDrawerIndicatorEnabled) {
357            if (enable) {
358                setActionBarUpIndicator((Drawable) mSlider,
359                        mDrawerLayout.isDrawerOpen(GravityCompat.START) ?
360                                mCloseDrawerContentDescRes : mOpenDrawerContentDescRes);
361            } else {
362                setActionBarUpIndicator(mHomeAsUpIndicator, 0);
363            }
364            mDrawerIndicatorEnabled = enable;
365        }
366    }
367
368    /**
369     * @return DrawerArrowDrawable that is currently shown by the ActionBarDrawerToggle.
370     */
371    @NonNull
372    public DrawerArrowDrawable getDrawerArrowDrawable() {
373        return mSlider;
374    }
375
376    /**
377     * Sets the DrawerArrowDrawable that should be shown by this ActionBarDrawerToggle.
378     *
379     * @param drawable DrawerArrowDrawable that should be shown by this ActionBarDrawerToggle.
380     */
381    public void setDrawerArrowDrawable(@NonNull DrawerArrowDrawable drawable) {
382        mSlider = drawable;
383        syncState();
384    }
385
386    /**
387     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
388     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
389     * through to this method from your own listener object.
390     *
391     * @param drawerView  The child view that was moved
392     * @param slideOffset The new offset of this drawer within its range, from 0-1
393     */
394    @Override
395    public void onDrawerSlide(View drawerView, float slideOffset) {
396        setPosition(Math.min(1f, Math.max(0, slideOffset)));
397    }
398
399    /**
400     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
401     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
402     * through to this method from your own listener object.
403     *
404     * @param drawerView Drawer view that is now open
405     */
406    @Override
407    public void onDrawerOpened(View drawerView) {
408        setPosition(1);
409        if (mDrawerIndicatorEnabled) {
410            setActionBarDescription(mCloseDrawerContentDescRes);
411        }
412    }
413
414    /**
415     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
416     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
417     * through to this method from your own listener object.
418     *
419     * @param drawerView Drawer view that is now closed
420     */
421    @Override
422    public void onDrawerClosed(View drawerView) {
423        setPosition(0);
424        if (mDrawerIndicatorEnabled) {
425            setActionBarDescription(mOpenDrawerContentDescRes);
426        }
427    }
428
429    /**
430     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
431     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
432     * through to this method from your own listener object.
433     *
434     * @param newState The new drawer motion state
435     */
436    @Override
437    public void onDrawerStateChanged(int newState) {
438    }
439
440    /**
441     * Returns the fallback listener for Navigation icon click events.
442     *
443     * @return The click listener which receives Navigation click events from Toolbar when
444     * drawer indicator is disabled.
445     * @see #setToolbarNavigationClickListener(android.view.View.OnClickListener)
446     * @see #setDrawerIndicatorEnabled(boolean)
447     * @see #isDrawerIndicatorEnabled()
448     */
449    public View.OnClickListener getToolbarNavigationClickListener() {
450        return mToolbarNavigationClickListener;
451    }
452
453    /**
454     * When DrawerToggle is constructed with a Toolbar, it sets the click listener on
455     * the Navigation icon. If you want to listen for clicks on the Navigation icon when
456     * DrawerToggle is disabled ({@link #setDrawerIndicatorEnabled(boolean)}, you should call this
457     * method with your listener and DrawerToggle will forward click events to that listener
458     * when drawer indicator is disabled.
459     *
460     * @see #setDrawerIndicatorEnabled(boolean)
461     */
462    public void setToolbarNavigationClickListener(
463            View.OnClickListener onToolbarNavigationClickListener) {
464        mToolbarNavigationClickListener = onToolbarNavigationClickListener;
465    }
466
467    void setActionBarUpIndicator(Drawable upDrawable, int contentDescRes) {
468        if (!mWarnedForDisplayHomeAsUp && !mActivityImpl.isNavigationVisible()) {
469            Log.w("ActionBarDrawerToggle", "DrawerToggle may not show up because NavigationIcon"
470                    + " is not visible. You may need to call "
471                    + "actionbar.setDisplayHomeAsUpEnabled(true);");
472            mWarnedForDisplayHomeAsUp = true;
473        }
474        mActivityImpl.setActionBarUpIndicator(upDrawable, contentDescRes);
475    }
476
477    void setActionBarDescription(int contentDescRes) {
478        mActivityImpl.setActionBarDescription(contentDescRes);
479    }
480
481    Drawable getThemeUpIndicator() {
482        return mActivityImpl.getThemeUpIndicator();
483    }
484
485    private void setPosition(float position) {
486        if (position == 1f) {
487            mSlider.setVerticalMirror(true);
488        } else if (position == 0f) {
489            mSlider.setVerticalMirror(false);
490        }
491        mSlider.setProgress(position);
492    }
493
494    /**
495     * Delegate if SDK version is between honeycomb and JBMR2
496     */
497    private static class HoneycombDelegate implements Delegate {
498
499        final Activity mActivity;
500        ActionBarDrawerToggleHoneycomb.SetIndicatorInfo mSetIndicatorInfo;
501
502        HoneycombDelegate(Activity activity) {
503            mActivity = activity;
504        }
505
506        @Override
507        public Drawable getThemeUpIndicator() {
508            return ActionBarDrawerToggleHoneycomb.getThemeUpIndicator(mActivity);
509        }
510
511        @Override
512        public Context getActionBarThemedContext() {
513            final ActionBar actionBar = mActivity.getActionBar();
514            final Context context;
515            if (actionBar != null) {
516                context = actionBar.getThemedContext();
517            } else {
518                context = mActivity;
519            }
520            return context;
521        }
522
523        @Override
524        public boolean isNavigationVisible() {
525            final ActionBar actionBar = mActivity.getActionBar();
526            return actionBar != null
527                    && (actionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0;
528        }
529
530        @Override
531        public void setActionBarUpIndicator(Drawable themeImage, int contentDescRes) {
532            final ActionBar actionBar = mActivity.getActionBar();
533            if (actionBar != null) {
534                actionBar.setDisplayShowHomeEnabled(true);
535                mSetIndicatorInfo = ActionBarDrawerToggleHoneycomb.setActionBarUpIndicator(
536                        mSetIndicatorInfo, mActivity, themeImage, contentDescRes);
537                actionBar.setDisplayShowHomeEnabled(false);
538            }
539        }
540
541        @Override
542        public void setActionBarDescription(int contentDescRes) {
543            mSetIndicatorInfo = ActionBarDrawerToggleHoneycomb.setActionBarDescription(
544                    mSetIndicatorInfo, mActivity, contentDescRes);
545        }
546    }
547
548    /**
549     * Delegate if SDK version is JB MR2 or newer
550     */
551    private static class JellybeanMr2Delegate implements Delegate {
552
553        final Activity mActivity;
554
555        JellybeanMr2Delegate(Activity activity) {
556            mActivity = activity;
557        }
558
559        @Override
560        public Drawable getThemeUpIndicator() {
561            final TypedArray a = getActionBarThemedContext().obtainStyledAttributes(null,
562                    new int[]{android.R.attr.homeAsUpIndicator}, android.R.attr.actionBarStyle, 0);
563            final Drawable result = a.getDrawable(0);
564            a.recycle();
565            return result;
566        }
567
568        @Override
569        public Context getActionBarThemedContext() {
570            final ActionBar actionBar = mActivity.getActionBar();
571            final Context context;
572            if (actionBar != null) {
573                context = actionBar.getThemedContext();
574            } else {
575                context = mActivity;
576            }
577            return context;
578        }
579
580        @Override
581        public boolean isNavigationVisible() {
582            final ActionBar actionBar = mActivity.getActionBar();
583            return actionBar != null &&
584                    (actionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0;
585        }
586
587        @Override
588        public void setActionBarUpIndicator(Drawable drawable, int contentDescRes) {
589            final ActionBar actionBar = mActivity.getActionBar();
590            if (actionBar != null) {
591                actionBar.setHomeAsUpIndicator(drawable);
592                actionBar.setHomeActionContentDescription(contentDescRes);
593            }
594        }
595
596        @Override
597        public void setActionBarDescription(int contentDescRes) {
598            final ActionBar actionBar = mActivity.getActionBar();
599            if (actionBar != null) {
600                actionBar.setHomeActionContentDescription(contentDescRes);
601            }
602        }
603    }
604
605    /**
606     * Used when DrawerToggle is initialized with a Toolbar
607     */
608    static class ToolbarCompatDelegate implements Delegate {
609
610        final Toolbar mToolbar;
611        final Drawable mDefaultUpIndicator;
612        final CharSequence mDefaultContentDescription;
613
614        ToolbarCompatDelegate(Toolbar toolbar) {
615            mToolbar = toolbar;
616            mDefaultUpIndicator = toolbar.getNavigationIcon();
617            mDefaultContentDescription = toolbar.getNavigationContentDescription();
618        }
619
620        @Override
621        public void setActionBarUpIndicator(Drawable upDrawable, @StringRes int contentDescRes) {
622            mToolbar.setNavigationIcon(upDrawable);
623            setActionBarDescription(contentDescRes);
624        }
625
626        @Override
627        public void setActionBarDescription(@StringRes int contentDescRes) {
628            if (contentDescRes == 0) {
629                mToolbar.setNavigationContentDescription(mDefaultContentDescription);
630            } else {
631                mToolbar.setNavigationContentDescription(contentDescRes);
632            }
633        }
634
635        @Override
636        public Drawable getThemeUpIndicator() {
637            return mDefaultUpIndicator;
638        }
639
640        @Override
641        public Context getActionBarThemedContext() {
642            return mToolbar.getContext();
643        }
644
645        @Override
646        public boolean isNavigationVisible() {
647            return true;
648        }
649    }
650
651    /**
652     * Fallback delegate
653     */
654    static class DummyDelegate implements Delegate {
655        final Activity mActivity;
656
657        DummyDelegate(Activity activity) {
658            mActivity = activity;
659        }
660
661        @Override
662        public void setActionBarUpIndicator(Drawable upDrawable, @StringRes int contentDescRes) {
663
664        }
665
666        @Override
667        public void setActionBarDescription(@StringRes int contentDescRes) {
668
669        }
670
671        @Override
672        public Drawable getThemeUpIndicator() {
673            return null;
674        }
675
676        @Override
677        public Context getActionBarThemedContext() {
678            return mActivity;
679        }
680
681        @Override
682        public boolean isNavigationVisible() {
683            return true;
684        }
685    }
686}
687