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  */
16 
17 package android.support.v7.internal.app;
18 
19 import android.app.Dialog;
20 import android.content.Context;
21 import android.content.res.Configuration;
22 import android.content.res.Resources;
23 import android.content.res.TypedArray;
24 import android.graphics.drawable.Drawable;
25 import android.os.Build;
26 import android.support.v4.app.FragmentActivity;
27 import android.support.v4.app.FragmentTransaction;
28 import android.support.v4.view.ViewCompat;
29 import android.support.v4.view.ViewPropertyAnimatorCompat;
30 import android.support.v4.view.ViewPropertyAnimatorListener;
31 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
32 import android.support.v4.view.ViewPropertyAnimatorUpdateListener;
33 import android.support.v7.app.ActionBar;
34 import android.support.v7.app.ActionBarActivity;
35 import android.support.v7.appcompat.R;
36 import android.support.v7.internal.view.ActionBarPolicy;
37 import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet;
38 import android.support.v7.internal.view.SupportMenuInflater;
39 import android.support.v7.internal.view.menu.MenuBuilder;
40 import android.support.v7.internal.view.menu.MenuPopupHelper;
41 import android.support.v7.internal.view.menu.SubMenuBuilder;
42 import android.support.v7.internal.widget.ActionBarContainer;
43 import android.support.v7.internal.widget.ActionBarContextView;
44 import android.support.v7.internal.widget.ActionBarOverlayLayout;
45 import android.support.v7.internal.widget.DecorToolbar;
46 import android.support.v7.internal.widget.TintManager;
47 import android.support.v7.internal.widget.ScrollingTabContainerView;
48 import android.support.v7.view.ActionMode;
49 import android.support.v7.widget.Toolbar;
50 import android.util.TypedValue;
51 import android.view.ContextThemeWrapper;
52 import android.view.LayoutInflater;
53 import android.view.Menu;
54 import android.view.MenuInflater;
55 import android.view.MenuItem;
56 import android.view.View;
57 import android.view.ViewParent;
58 import android.view.Window;
59 import android.view.accessibility.AccessibilityEvent;
60 import android.view.animation.AnimationUtils;
61 import android.widget.SpinnerAdapter;
62 
63 import java.lang.ref.WeakReference;
64 import java.util.ArrayList;
65 
66 /**
67  * WindowDecorActionBar is the ActionBar implementation used
68  * by devices of all screen sizes as part of the window decor layout.
69  * If it detects a compatible decor, it will split contextual modes
70  * across both the ActionBarView at the top of the screen and
71  * a horizontal LinearLayout at the bottom which is normally hidden.
72  *
73  * @hide
74  */
75 public class WindowDecorActionBar extends ActionBar implements
76         ActionBarOverlayLayout.ActionBarVisibilityCallback {
77     private static final String TAG = "WindowDecorActionBar";
78 
79     /**
80      * Only allow show/hide animations on ICS+, as that is what ViewPropertyAnimatorCompat supports
81      */
82     private static final boolean ALLOW_SHOW_HIDE_ANIMATIONS = Build.VERSION.SDK_INT >= 14;
83 
84     private Context mContext;
85     private Context mThemedContext;
86     private FragmentActivity mActivity;
87     private Dialog mDialog;
88 
89     private ActionBarOverlayLayout mOverlayLayout;
90     private ActionBarContainer mContainerView;
91     private DecorToolbar mDecorToolbar;
92     private ActionBarContextView mContextView;
93     private ActionBarContainer mSplitView;
94     private View mContentView;
95     private ScrollingTabContainerView mTabScrollView;
96 
97     private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
98 
99     private TabImpl mSelectedTab;
100     private int mSavedTabPosition = INVALID_POSITION;
101 
102     private boolean mDisplayHomeAsUpSet;
103 
104     ActionModeImpl mActionMode;
105     ActionMode mDeferredDestroyActionMode;
106     ActionMode.Callback mDeferredModeDestroyCallback;
107 
108     private boolean mLastMenuVisibility;
109     private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
110             new ArrayList<OnMenuVisibilityListener>();
111 
112     private static final int CONTEXT_DISPLAY_NORMAL = 0;
113     private static final int CONTEXT_DISPLAY_SPLIT = 1;
114 
115     private static final int INVALID_POSITION = -1;
116 
117     private int mContextDisplayMode;
118     private boolean mHasEmbeddedTabs;
119 
120     private int mCurWindowVisibility = View.VISIBLE;
121 
122     private boolean mContentAnimations = true;
123     private boolean mHiddenByApp;
124     private boolean mHiddenBySystem;
125     private boolean mShowingForMode;
126 
127     private boolean mNowShowing = true;
128 
129     private ViewPropertyAnimatorCompatSet mCurrentShowAnim;
130     private boolean mShowHideAnimationEnabled;
131     boolean mHideOnContentScroll;
132 
133     private TintManager mTintManager;
134 
135     final ViewPropertyAnimatorListener mHideListener = new ViewPropertyAnimatorListenerAdapter() {
136         @Override
137         public void onAnimationEnd(View view) {
138             if (mContentAnimations && mContentView != null) {
139                 ViewCompat.setTranslationY(mContentView, 0f);
140                 ViewCompat.setTranslationY(mContainerView, 0f);
141             }
142             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
143                 mSplitView.setVisibility(View.GONE);
144             }
145             mContainerView.setVisibility(View.GONE);
146             mContainerView.setTransitioning(false);
147             mCurrentShowAnim = null;
148             completeDeferredDestroyActionMode();
149             if (mOverlayLayout != null) {
150                 ViewCompat.requestApplyInsets(mOverlayLayout);
151             }
152         }
153     };
154 
155     final ViewPropertyAnimatorListener mShowListener = new ViewPropertyAnimatorListenerAdapter() {
156         @Override
157         public void onAnimationEnd(View view) {
158             mCurrentShowAnim = null;
159             mContainerView.requestLayout();
160         }
161     };
162 
163     final ViewPropertyAnimatorUpdateListener mUpdateListener =
164             new ViewPropertyAnimatorUpdateListener() {
165                 @Override
166                 public void onAnimationUpdate(View view) {
167                     final ViewParent parent = mContainerView.getParent();
168                     ((View) parent).invalidate();
169                 }
170             };
171 
WindowDecorActionBar(ActionBarActivity activity, boolean overlayMode)172     public WindowDecorActionBar(ActionBarActivity activity, boolean overlayMode) {
173         mActivity = activity;
174         Window window = activity.getWindow();
175         View decor = window.getDecorView();
176         init(decor);
177         if (!overlayMode) {
178             mContentView = decor.findViewById(android.R.id.content);
179         }
180     }
181 
WindowDecorActionBar(Dialog dialog)182     public WindowDecorActionBar(Dialog dialog) {
183         mDialog = dialog;
184         init(dialog.getWindow().getDecorView());
185     }
186 
187     /**
188      * Only for edit mode.
189      * @hide
190      */
WindowDecorActionBar(View layout)191     public WindowDecorActionBar(View layout) {
192         assert layout.isInEditMode();
193         init(layout);
194     }
195 
init(View decor)196     private void init(View decor) {
197         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(R.id.decor_content_parent);
198         if (mOverlayLayout != null) {
199             mOverlayLayout.setActionBarVisibilityCallback(this);
200         }
201         mDecorToolbar = getDecorToolbar(decor.findViewById(R.id.action_bar));
202         mContextView = (ActionBarContextView) decor.findViewById(
203                 R.id.action_context_bar);
204         mContainerView = (ActionBarContainer) decor.findViewById(
205                 R.id.action_bar_container);
206 
207          mSplitView = (ActionBarContainer) decor.findViewById(R.id.split_action_bar);
208 
209         if (mDecorToolbar == null || mContextView == null || mContainerView == null) {
210             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
211                     "with a compatible window decor layout");
212         }
213 
214         mContext = mDecorToolbar.getContext();
215         mContextDisplayMode = mDecorToolbar.isSplit() ?
216                 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
217 
218         // This was initially read from the action bar style
219         final int current = mDecorToolbar.getDisplayOptions();
220         final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
221         if (homeAsUp) {
222             mDisplayHomeAsUpSet = true;
223         }
224 
225         ActionBarPolicy abp = ActionBarPolicy.get(mContext);
226         setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp);
227         setHasEmbeddedTabs(abp.hasEmbeddedTabs());
228 
229         final TypedArray a = mContext.obtainStyledAttributes(null,
230                 R.styleable.ActionBar,
231                 R.attr.actionBarStyle, 0);
232         if (a.getBoolean(R.styleable.ActionBar_hideOnContentScroll, false)) {
233             setHideOnContentScrollEnabled(true);
234         }
235         final int elevation = a.getDimensionPixelSize(R.styleable.ActionBar_elevation, 0);
236         if (elevation != 0) {
237             setElevation(elevation);
238         }
239         a.recycle();
240     }
241 
getDecorToolbar(View view)242     private DecorToolbar getDecorToolbar(View view) {
243         if (view instanceof DecorToolbar) {
244             return (DecorToolbar) view;
245         } else if (view instanceof Toolbar) {
246             return ((Toolbar) view).getWrapper();
247         } else {
248             throw new IllegalStateException("Can't make a decor toolbar out of " +
249                     view.getClass().getSimpleName());
250         }
251     }
252 
253     @Override
setElevation(float elevation)254     public void setElevation(float elevation) {
255         ViewCompat.setElevation(mContainerView, elevation);
256         if (mSplitView != null) {
257             ViewCompat.setElevation(mSplitView, elevation);
258         }
259     }
260 
261     @Override
getElevation()262     public float getElevation() {
263         return ViewCompat.getElevation(mContainerView);
264     }
265 
onConfigurationChanged(Configuration newConfig)266     public void onConfigurationChanged(Configuration newConfig) {
267         setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
268     }
269 
setHasEmbeddedTabs(boolean hasEmbeddedTabs)270     private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) {
271         mHasEmbeddedTabs = hasEmbeddedTabs;
272         // Switch tab layout configuration if needed
273         if (!mHasEmbeddedTabs) {
274             mDecorToolbar.setEmbeddedTabView(null);
275             mContainerView.setTabContainer(mTabScrollView);
276         } else {
277             mContainerView.setTabContainer(null);
278             mDecorToolbar.setEmbeddedTabView(mTabScrollView);
279         }
280         final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
281         if (mTabScrollView != null) {
282             if (isInTabMode) {
283                 mTabScrollView.setVisibility(View.VISIBLE);
284                 if (mOverlayLayout != null) {
285                     ViewCompat.requestApplyInsets(mOverlayLayout);
286                 }
287             } else {
288                 mTabScrollView.setVisibility(View.GONE);
289             }
290         }
291         mDecorToolbar.setCollapsible(!mHasEmbeddedTabs && isInTabMode);
292         mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
293     }
294 
ensureTabsExist()295     private void ensureTabsExist() {
296         if (mTabScrollView != null) {
297             return;
298         }
299 
300         ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext);
301 
302         if (mHasEmbeddedTabs) {
303             tabScroller.setVisibility(View.VISIBLE);
304             mDecorToolbar.setEmbeddedTabView(tabScroller);
305         } else {
306             if (getNavigationMode() == NAVIGATION_MODE_TABS) {
307                 tabScroller.setVisibility(View.VISIBLE);
308                 if (mOverlayLayout != null) {
309                     ViewCompat.requestApplyInsets(mOverlayLayout);
310                 }
311             } else {
312                 tabScroller.setVisibility(View.GONE);
313             }
314             mContainerView.setTabContainer(tabScroller);
315         }
316         mTabScrollView = tabScroller;
317     }
318 
completeDeferredDestroyActionMode()319     void completeDeferredDestroyActionMode() {
320         if (mDeferredModeDestroyCallback != null) {
321             mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
322             mDeferredDestroyActionMode = null;
323             mDeferredModeDestroyCallback = null;
324         }
325     }
326 
onWindowVisibilityChanged(int visibility)327     public void onWindowVisibilityChanged(int visibility) {
328         mCurWindowVisibility = visibility;
329     }
330 
331     /**
332      * Enables or disables animation between show/hide states.
333      * If animation is disabled using this method, animations in progress
334      * will be finished.
335      *
336      * @param enabled true to animate, false to not animate.
337      */
setShowHideAnimationEnabled(boolean enabled)338     public void setShowHideAnimationEnabled(boolean enabled) {
339         mShowHideAnimationEnabled = enabled;
340         if (!enabled && mCurrentShowAnim != null) {
341             mCurrentShowAnim.cancel();
342         }
343     }
344 
addOnMenuVisibilityListener(OnMenuVisibilityListener listener)345     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
346         mMenuVisibilityListeners.add(listener);
347     }
348 
removeOnMenuVisibilityListener(OnMenuVisibilityListener listener)349     public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
350         mMenuVisibilityListeners.remove(listener);
351     }
352 
dispatchMenuVisibilityChanged(boolean isVisible)353     public void dispatchMenuVisibilityChanged(boolean isVisible) {
354         if (isVisible == mLastMenuVisibility) {
355             return;
356         }
357         mLastMenuVisibility = isVisible;
358 
359         final int count = mMenuVisibilityListeners.size();
360         for (int i = 0; i < count; i++) {
361             mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
362         }
363     }
364 
365     @Override
setCustomView(int resId)366     public void setCustomView(int resId) {
367         setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId,
368                 mDecorToolbar.getViewGroup(), false));
369     }
370 
371     @Override
setDisplayUseLogoEnabled(boolean useLogo)372     public void setDisplayUseLogoEnabled(boolean useLogo) {
373         setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
374     }
375 
376     @Override
setDisplayShowHomeEnabled(boolean showHome)377     public void setDisplayShowHomeEnabled(boolean showHome) {
378         setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
379     }
380 
381     @Override
setDisplayHomeAsUpEnabled(boolean showHomeAsUp)382     public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
383         setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
384     }
385 
386     @Override
setDisplayShowTitleEnabled(boolean showTitle)387     public void setDisplayShowTitleEnabled(boolean showTitle) {
388         setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
389     }
390 
391     @Override
setDisplayShowCustomEnabled(boolean showCustom)392     public void setDisplayShowCustomEnabled(boolean showCustom) {
393         setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
394     }
395 
396     @Override
setHomeButtonEnabled(boolean enable)397     public void setHomeButtonEnabled(boolean enable) {
398         mDecorToolbar.setHomeButtonEnabled(enable);
399     }
400 
401     @Override
setTitle(int resId)402     public void setTitle(int resId) {
403         setTitle(mContext.getString(resId));
404     }
405 
406     @Override
setSubtitle(int resId)407     public void setSubtitle(int resId) {
408         setSubtitle(mContext.getString(resId));
409     }
410 
setSelectedNavigationItem(int position)411     public void setSelectedNavigationItem(int position) {
412         switch (mDecorToolbar.getNavigationMode()) {
413             case NAVIGATION_MODE_TABS:
414                 selectTab(mTabs.get(position));
415                 break;
416             case NAVIGATION_MODE_LIST:
417                 mDecorToolbar.setDropdownSelectedPosition(position);
418                 break;
419             default:
420                 throw new IllegalStateException(
421                         "setSelectedNavigationIndex not valid for current navigation mode");
422         }
423     }
424 
removeAllTabs()425     public void removeAllTabs() {
426         cleanupTabs();
427     }
428 
cleanupTabs()429     private void cleanupTabs() {
430         if (mSelectedTab != null) {
431             selectTab(null);
432         }
433         mTabs.clear();
434         if (mTabScrollView != null) {
435             mTabScrollView.removeAllTabs();
436         }
437         mSavedTabPosition = INVALID_POSITION;
438     }
439 
setTitle(CharSequence title)440     public void setTitle(CharSequence title) {
441         mDecorToolbar.setTitle(title);
442     }
443 
444     @Override
setWindowTitle(CharSequence title)445     public void setWindowTitle(CharSequence title) {
446         mDecorToolbar.setWindowTitle(title);
447     }
448 
setSubtitle(CharSequence subtitle)449     public void setSubtitle(CharSequence subtitle) {
450         mDecorToolbar.setSubtitle(subtitle);
451     }
452 
setDisplayOptions(int options)453     public void setDisplayOptions(int options) {
454         if ((options & DISPLAY_HOME_AS_UP) != 0) {
455             mDisplayHomeAsUpSet = true;
456         }
457         mDecorToolbar.setDisplayOptions(options);
458     }
459 
setDisplayOptions(int options, int mask)460     public void setDisplayOptions(int options, int mask) {
461         final int current = mDecorToolbar.getDisplayOptions();
462         if ((mask & DISPLAY_HOME_AS_UP) != 0) {
463             mDisplayHomeAsUpSet = true;
464         }
465         mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask));
466     }
467 
setBackgroundDrawable(Drawable d)468     public void setBackgroundDrawable(Drawable d) {
469         mContainerView.setPrimaryBackground(d);
470     }
471 
setStackedBackgroundDrawable(Drawable d)472     public void setStackedBackgroundDrawable(Drawable d) {
473         mContainerView.setStackedBackground(d);
474     }
475 
setSplitBackgroundDrawable(Drawable d)476     public void setSplitBackgroundDrawable(Drawable d) {
477         if (mSplitView != null) {
478             mSplitView.setSplitBackground(d);
479         }
480     }
481 
getCustomView()482     public View getCustomView() {
483         return mDecorToolbar.getCustomView();
484     }
485 
getTitle()486     public CharSequence getTitle() {
487         return mDecorToolbar.getTitle();
488     }
489 
getSubtitle()490     public CharSequence getSubtitle() {
491         return mDecorToolbar.getSubtitle();
492     }
493 
getNavigationMode()494     public int getNavigationMode() {
495         return mDecorToolbar.getNavigationMode();
496     }
497 
getDisplayOptions()498     public int getDisplayOptions() {
499         return mDecorToolbar.getDisplayOptions();
500     }
501 
startActionMode(ActionMode.Callback callback)502     public ActionMode startActionMode(ActionMode.Callback callback) {
503         if (mActionMode != null) {
504             mActionMode.finish();
505         }
506 
507         mOverlayLayout.setHideOnContentScrollEnabled(false);
508         mContextView.killMode();
509         ActionModeImpl mode = new ActionModeImpl(mContextView.getContext(), callback);
510         if (mode.dispatchOnCreate()) {
511             mode.invalidate();
512             mContextView.initForMode(mode);
513             animateToMode(true);
514             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
515                 // TODO animate this
516                 if (mSplitView.getVisibility() != View.VISIBLE) {
517                     mSplitView.setVisibility(View.VISIBLE);
518                     if (mOverlayLayout != null) {
519                         ViewCompat.requestApplyInsets(mOverlayLayout);
520                     }
521                 }
522             }
523             mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
524             mActionMode = mode;
525             return mode;
526         }
527         return null;
528     }
529 
configureTab(Tab tab, int position)530     private void configureTab(Tab tab, int position) {
531         final TabImpl tabi = (TabImpl) tab;
532         final ActionBar.TabListener callback = tabi.getCallback();
533 
534         if (callback == null) {
535             throw new IllegalStateException("Action Bar Tab must have a Callback");
536         }
537 
538         tabi.setPosition(position);
539         mTabs.add(position, tabi);
540 
541         final int count = mTabs.size();
542         for (int i = position + 1; i < count; i++) {
543             mTabs.get(i).setPosition(i);
544         }
545     }
546 
547     @Override
addTab(Tab tab)548     public void addTab(Tab tab) {
549         addTab(tab, mTabs.isEmpty());
550     }
551 
552     @Override
addTab(Tab tab, int position)553     public void addTab(Tab tab, int position) {
554         addTab(tab, position, mTabs.isEmpty());
555     }
556 
557     @Override
addTab(Tab tab, boolean setSelected)558     public void addTab(Tab tab, boolean setSelected) {
559         ensureTabsExist();
560         mTabScrollView.addTab(tab, setSelected);
561         configureTab(tab, mTabs.size());
562         if (setSelected) {
563             selectTab(tab);
564         }
565     }
566 
567     @Override
addTab(Tab tab, int position, boolean setSelected)568     public void addTab(Tab tab, int position, boolean setSelected) {
569         ensureTabsExist();
570         mTabScrollView.addTab(tab, position, setSelected);
571         configureTab(tab, position);
572         if (setSelected) {
573             selectTab(tab);
574         }
575     }
576 
577     @Override
newTab()578     public Tab newTab() {
579         return new TabImpl();
580     }
581 
582     @Override
removeTab(Tab tab)583     public void removeTab(Tab tab) {
584         removeTabAt(tab.getPosition());
585     }
586 
587     @Override
removeTabAt(int position)588     public void removeTabAt(int position) {
589         if (mTabScrollView == null) {
590             // No tabs around to remove
591             return;
592         }
593 
594         int selectedTabPosition = mSelectedTab != null
595                 ? mSelectedTab.getPosition() : mSavedTabPosition;
596         mTabScrollView.removeTabAt(position);
597         TabImpl removedTab = mTabs.remove(position);
598         if (removedTab != null) {
599             removedTab.setPosition(-1);
600         }
601 
602         final int newTabCount = mTabs.size();
603         for (int i = position; i < newTabCount; i++) {
604             mTabs.get(i).setPosition(i);
605         }
606 
607         if (selectedTabPosition == position) {
608             selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
609         }
610     }
611 
612     @Override
selectTab(Tab tab)613     public void selectTab(Tab tab) {
614         if (getNavigationMode() != NAVIGATION_MODE_TABS) {
615             mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
616             return;
617         }
618 
619         final FragmentTransaction trans = mDecorToolbar.getViewGroup().isInEditMode() ? null :
620                 mActivity.getSupportFragmentManager().beginTransaction().disallowAddToBackStack();
621 
622         if (mSelectedTab == tab) {
623             if (mSelectedTab != null) {
624                 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
625                 mTabScrollView.animateToTab(tab.getPosition());
626             }
627         } else {
628             mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
629             if (mSelectedTab != null) {
630                 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
631             }
632             mSelectedTab = (TabImpl) tab;
633             if (mSelectedTab != null) {
634                 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
635             }
636         }
637 
638         if (trans != null && !trans.isEmpty()) {
639             trans.commit();
640         }
641     }
642 
643     @Override
getSelectedTab()644     public Tab getSelectedTab() {
645         return mSelectedTab;
646     }
647 
648     @Override
getHeight()649     public int getHeight() {
650         return mContainerView.getHeight();
651     }
652 
enableContentAnimations(boolean enabled)653     public void enableContentAnimations(boolean enabled) {
654         mContentAnimations = enabled;
655     }
656 
657     @Override
show()658     public void show() {
659         if (mHiddenByApp) {
660             mHiddenByApp = false;
661             updateVisibility(false);
662         }
663     }
664 
showForActionMode()665     private void showForActionMode() {
666         if (!mShowingForMode) {
667             mShowingForMode = true;
668             if (mOverlayLayout != null) {
669                 mOverlayLayout.setShowingForActionMode(true);
670             }
671             updateVisibility(false);
672         }
673     }
674 
showForSystem()675     public void showForSystem() {
676         if (mHiddenBySystem) {
677             mHiddenBySystem = false;
678             updateVisibility(true);
679         }
680     }
681 
682     @Override
hide()683     public void hide() {
684         if (!mHiddenByApp) {
685             mHiddenByApp = true;
686             updateVisibility(false);
687         }
688     }
689 
hideForActionMode()690     private void hideForActionMode() {
691         if (mShowingForMode) {
692             mShowingForMode = false;
693             if (mOverlayLayout != null) {
694                 mOverlayLayout.setShowingForActionMode(false);
695             }
696             updateVisibility(false);
697         }
698     }
699 
hideForSystem()700     public void hideForSystem() {
701         if (!mHiddenBySystem) {
702             mHiddenBySystem = true;
703             updateVisibility(true);
704         }
705     }
706 
707     @Override
setHideOnContentScrollEnabled(boolean hideOnContentScroll)708     public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
709         if (hideOnContentScroll && !mOverlayLayout.isInOverlayMode()) {
710             throw new IllegalStateException("Action bar must be in overlay mode " +
711                     "(Window.FEATURE_OVERLAY_ACTION_BAR) to enable hide on content scroll");
712         }
713         mHideOnContentScroll = hideOnContentScroll;
714         mOverlayLayout.setHideOnContentScrollEnabled(hideOnContentScroll);
715     }
716 
717     @Override
isHideOnContentScrollEnabled()718     public boolean isHideOnContentScrollEnabled() {
719         return mOverlayLayout.isHideOnContentScrollEnabled();
720     }
721 
722     @Override
getHideOffset()723     public int getHideOffset() {
724         return mOverlayLayout.getActionBarHideOffset();
725     }
726 
727     @Override
setHideOffset(int offset)728     public void setHideOffset(int offset) {
729         if (offset != 0 && !mOverlayLayout.isInOverlayMode()) {
730             throw new IllegalStateException("Action bar must be in overlay mode " +
731                     "(Window.FEATURE_OVERLAY_ACTION_BAR) to set a non-zero hide offset");
732         }
733         mOverlayLayout.setActionBarHideOffset(offset);
734     }
735 
checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem, boolean showingForMode)736     private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem,
737             boolean showingForMode) {
738         if (showingForMode) {
739             return true;
740         } else if (hiddenByApp || hiddenBySystem) {
741             return false;
742         } else {
743             return true;
744         }
745     }
746 
updateVisibility(boolean fromSystem)747     private void updateVisibility(boolean fromSystem) {
748         // Based on the current state, should we be hidden or shown?
749         final boolean shown = checkShowingFlags(mHiddenByApp, mHiddenBySystem,
750                 mShowingForMode);
751 
752         if (shown) {
753             if (!mNowShowing) {
754                 mNowShowing = true;
755                 doShow(fromSystem);
756             }
757         } else {
758             if (mNowShowing) {
759                 mNowShowing = false;
760                 doHide(fromSystem);
761             }
762         }
763     }
764 
doShow(boolean fromSystem)765     public void doShow(boolean fromSystem) {
766         if (mCurrentShowAnim != null) {
767             mCurrentShowAnim.cancel();
768         }
769         mContainerView.setVisibility(View.VISIBLE);
770 
771         if (mCurWindowVisibility == View.VISIBLE && ALLOW_SHOW_HIDE_ANIMATIONS &&
772                 (mShowHideAnimationEnabled || fromSystem)) {
773             // because we're about to ask its window loc
774             ViewCompat.setTranslationY(mContainerView, 0f);
775             float startingY = -mContainerView.getHeight();
776             if (fromSystem) {
777                 int topLeft[] = {0, 0};
778                 mContainerView.getLocationInWindow(topLeft);
779                 startingY -= topLeft[1];
780             }
781             ViewCompat.setTranslationY(mContainerView, startingY);
782             ViewPropertyAnimatorCompatSet anim = new ViewPropertyAnimatorCompatSet();
783             ViewPropertyAnimatorCompat a = ViewCompat.animate(mContainerView).translationY(0f);
784             a.setUpdateListener(mUpdateListener);
785             anim.play(a);
786             if (mContentAnimations && mContentView != null) {
787                 ViewCompat.setTranslationY(mContentView, startingY);
788                 anim.play(ViewCompat.animate(mContentView).translationY(0f));
789             }
790             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
791                 ViewCompat.setTranslationY(mSplitView, mSplitView.getHeight());
792                 mSplitView.setVisibility(View.VISIBLE);
793                 anim.play(ViewCompat.animate(mSplitView).translationY(0f));
794             }
795             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
796                     android.R.anim.decelerate_interpolator));
797             anim.setDuration(250);
798             // If this is being shown from the system, add a small delay.
799             // This is because we will also be animating in the status bar,
800             // and these two elements can't be done in lock-step.  So we give
801             // a little time for the status bar to start its animation before
802             // the action bar animates.  (This corresponds to the corresponding
803             // case when hiding, where the status bar has a small delay before
804             // starting.)
805             anim.setListener(mShowListener);
806             mCurrentShowAnim = anim;
807             anim.start();
808         } else {
809             ViewCompat.setAlpha(mContainerView, 1f);
810             ViewCompat.setTranslationY(mContainerView, 0);
811             if (mContentAnimations && mContentView != null) {
812                 ViewCompat.setTranslationY(mContentView, 0);
813             }
814             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
815                 ViewCompat.setAlpha(mSplitView, 1f);
816                 ViewCompat.setTranslationY(mSplitView, 0);
817                 mSplitView.setVisibility(View.VISIBLE);
818             }
819             mShowListener.onAnimationEnd(null);
820         }
821         if (mOverlayLayout != null) {
822             ViewCompat.requestApplyInsets(mOverlayLayout);
823         }
824     }
825 
doHide(boolean fromSystem)826     public void doHide(boolean fromSystem) {
827         if (mCurrentShowAnim != null) {
828             mCurrentShowAnim.cancel();
829         }
830 
831         if (mCurWindowVisibility == View.VISIBLE && ALLOW_SHOW_HIDE_ANIMATIONS &&
832                 (mShowHideAnimationEnabled || fromSystem)) {
833             ViewCompat.setAlpha(mContainerView, 1f);
834             mContainerView.setTransitioning(true);
835             ViewPropertyAnimatorCompatSet anim = new ViewPropertyAnimatorCompatSet();
836             float endingY = -mContainerView.getHeight();
837             if (fromSystem) {
838                 int topLeft[] = {0, 0};
839                 mContainerView.getLocationInWindow(topLeft);
840                 endingY -= topLeft[1];
841             }
842             ViewPropertyAnimatorCompat a = ViewCompat.animate(mContainerView).translationY(endingY);
843             a.setUpdateListener(mUpdateListener);
844             anim.play(a);
845             if (mContentAnimations && mContentView != null) {
846                 anim.play(ViewCompat.animate(mContentView).translationY(endingY));
847             }
848             if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
849                 ViewCompat.setAlpha(mSplitView, 1f);
850                 anim.play(ViewCompat.animate(mSplitView).translationY(mSplitView.getHeight()));
851             }
852             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
853                     android.R.anim.accelerate_interpolator));
854             anim.setDuration(250);
855             anim.setListener(mHideListener);
856             mCurrentShowAnim = anim;
857             anim.start();
858         } else {
859             mHideListener.onAnimationEnd(null);
860         }
861     }
862 
isShowing()863     public boolean isShowing() {
864         final int height = getHeight();
865         // Take into account the case where the bar has a 0 height due to not being measured yet.
866         return mNowShowing && (height == 0 || getHideOffset() < height);
867     }
868 
animateToMode(boolean toActionMode)869     public void animateToMode(boolean toActionMode) {
870         if (toActionMode) {
871             showForActionMode();
872         } else {
873             hideForActionMode();
874         }
875 
876         mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
877         mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
878         // mTabScrollView's visibility is not affected by action mode.
879     }
880 
getThemedContext()881     public Context getThemedContext() {
882         if (mThemedContext == null) {
883             TypedValue outValue = new TypedValue();
884             Resources.Theme currentTheme = mContext.getTheme();
885             currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme, outValue, true);
886             final int targetThemeRes = outValue.resourceId;
887 
888             if (targetThemeRes != 0) {
889                 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
890             } else {
891                 mThemedContext = mContext;
892             }
893         }
894         return mThemedContext;
895     }
896 
897     @Override
isTitleTruncated()898     public boolean isTitleTruncated() {
899         return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
900     }
901 
902     @Override
setHomeAsUpIndicator(Drawable indicator)903     public void setHomeAsUpIndicator(Drawable indicator) {
904         mDecorToolbar.setNavigationIcon(indicator);
905     }
906 
907     @Override
setHomeAsUpIndicator(int resId)908     public void setHomeAsUpIndicator(int resId) {
909         mDecorToolbar.setNavigationIcon(resId);
910     }
911 
912     @Override
setHomeActionContentDescription(CharSequence description)913     public void setHomeActionContentDescription(CharSequence description) {
914         mDecorToolbar.setNavigationContentDescription(description);
915     }
916 
917     @Override
setHomeActionContentDescription(int resId)918     public void setHomeActionContentDescription(int resId) {
919         mDecorToolbar.setNavigationContentDescription(resId);
920     }
921 
922     @Override
onContentScrollStarted()923     public void onContentScrollStarted() {
924         if (mCurrentShowAnim != null) {
925             mCurrentShowAnim.cancel();
926             mCurrentShowAnim = null;
927         }
928     }
929 
930     @Override
onContentScrollStopped()931     public void onContentScrollStopped() {
932     }
933 
934     @Override
collapseActionView()935     public boolean collapseActionView() {
936         if (mDecorToolbar != null && mDecorToolbar.hasExpandedActionView()) {
937             mDecorToolbar.collapseActionView();
938             return true;
939         }
940         return false;
941     }
942 
943     /**
944      * @hide
945      */
946     public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
947         private final Context mActionModeContext;
948         private final MenuBuilder mMenu;
949 
950         private ActionMode.Callback mCallback;
951         private WeakReference<View> mCustomView;
952 
ActionModeImpl(Context context, ActionMode.Callback callback)953         public ActionModeImpl(Context context, ActionMode.Callback callback) {
954             mActionModeContext = context;
955             mCallback = callback;
956             mMenu = new MenuBuilder(context)
957                     .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
958             mMenu.setCallback(this);
959         }
960 
961         @Override
getMenuInflater()962         public MenuInflater getMenuInflater() {
963             return new SupportMenuInflater(mActionModeContext);
964         }
965 
966         @Override
getMenu()967         public Menu getMenu() {
968             return mMenu;
969         }
970 
971         @Override
finish()972         public void finish() {
973             if (mActionMode != this) {
974                 // Not the active action mode - no-op
975                 return;
976             }
977 
978             // If this change in state is going to cause the action bar
979             // to be hidden, defer the onDestroy callback until the animation
980             // is finished and associated relayout is about to happen. This lets
981             // apps better anticipate visibility and layout behavior.
982             if (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) {
983                 // With the current state but the action bar hidden, our
984                 // overall showing state is going to be false.
985                 mDeferredDestroyActionMode = this;
986                 mDeferredModeDestroyCallback = mCallback;
987             } else {
988                 mCallback.onDestroyActionMode(this);
989             }
990             mCallback = null;
991             animateToMode(false);
992 
993             // Clear out the context mode views after the animation finishes
994             mContextView.closeMode();
995             mDecorToolbar.getViewGroup().sendAccessibilityEvent(
996                     AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
997             mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
998 
999             mActionMode = null;
1000         }
1001 
1002         @Override
invalidate()1003         public void invalidate() {
1004             mMenu.stopDispatchingItemsChanged();
1005             try {
1006                 mCallback.onPrepareActionMode(this, mMenu);
1007             } finally {
1008                 mMenu.startDispatchingItemsChanged();
1009             }
1010         }
1011 
dispatchOnCreate()1012         public boolean dispatchOnCreate() {
1013             mMenu.stopDispatchingItemsChanged();
1014             try {
1015                 return mCallback.onCreateActionMode(this, mMenu);
1016             } finally {
1017                 mMenu.startDispatchingItemsChanged();
1018             }
1019         }
1020 
1021         @Override
setCustomView(View view)1022         public void setCustomView(View view) {
1023             mContextView.setCustomView(view);
1024             mCustomView = new WeakReference<View>(view);
1025         }
1026 
1027         @Override
setSubtitle(CharSequence subtitle)1028         public void setSubtitle(CharSequence subtitle) {
1029             mContextView.setSubtitle(subtitle);
1030         }
1031 
1032         @Override
setTitle(CharSequence title)1033         public void setTitle(CharSequence title) {
1034             mContextView.setTitle(title);
1035         }
1036 
1037         @Override
setTitle(int resId)1038         public void setTitle(int resId) {
1039             setTitle(mContext.getResources().getString(resId));
1040         }
1041 
1042         @Override
setSubtitle(int resId)1043         public void setSubtitle(int resId) {
1044             setSubtitle(mContext.getResources().getString(resId));
1045         }
1046 
1047         @Override
getTitle()1048         public CharSequence getTitle() {
1049             return mContextView.getTitle();
1050         }
1051 
1052         @Override
getSubtitle()1053         public CharSequence getSubtitle() {
1054             return mContextView.getSubtitle();
1055         }
1056 
1057         @Override
setTitleOptionalHint(boolean titleOptional)1058         public void setTitleOptionalHint(boolean titleOptional) {
1059             super.setTitleOptionalHint(titleOptional);
1060             mContextView.setTitleOptional(titleOptional);
1061         }
1062 
1063         @Override
isTitleOptional()1064         public boolean isTitleOptional() {
1065             return mContextView.isTitleOptional();
1066         }
1067 
1068         @Override
getCustomView()1069         public View getCustomView() {
1070             return mCustomView != null ? mCustomView.get() : null;
1071         }
1072 
onMenuItemSelected(MenuBuilder menu, MenuItem item)1073         public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
1074             if (mCallback != null) {
1075                 return mCallback.onActionItemClicked(this, item);
1076             } else {
1077                 return false;
1078             }
1079         }
1080 
onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing)1081         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
1082         }
1083 
onSubMenuSelected(SubMenuBuilder subMenu)1084         public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
1085             if (mCallback == null) {
1086                 return false;
1087             }
1088 
1089             if (!subMenu.hasVisibleItems()) {
1090                 return true;
1091             }
1092 
1093             new MenuPopupHelper(getThemedContext(), subMenu).show();
1094             return true;
1095         }
1096 
onCloseSubMenu(SubMenuBuilder menu)1097         public void onCloseSubMenu(SubMenuBuilder menu) {
1098         }
1099 
onMenuModeChange(MenuBuilder menu)1100         public void onMenuModeChange(MenuBuilder menu) {
1101             if (mCallback == null) {
1102                 return;
1103             }
1104             invalidate();
1105             mContextView.showOverflowMenu();
1106         }
1107     }
1108 
1109     /**
1110      * @hide
1111      */
1112     public class TabImpl extends ActionBar.Tab {
1113         private ActionBar.TabListener mCallback;
1114         private Object mTag;
1115         private Drawable mIcon;
1116         private CharSequence mText;
1117         private CharSequence mContentDesc;
1118         private int mPosition = -1;
1119         private View mCustomView;
1120 
1121         @Override
getTag()1122         public Object getTag() {
1123             return mTag;
1124         }
1125 
1126         @Override
setTag(Object tag)1127         public Tab setTag(Object tag) {
1128             mTag = tag;
1129             return this;
1130         }
1131 
getCallback()1132         public ActionBar.TabListener getCallback() {
1133             return mCallback;
1134         }
1135 
1136         @Override
setTabListener(ActionBar.TabListener callback)1137         public Tab setTabListener(ActionBar.TabListener callback) {
1138             mCallback = callback;
1139             return this;
1140         }
1141 
1142         @Override
getCustomView()1143         public View getCustomView() {
1144             return mCustomView;
1145         }
1146 
1147         @Override
setCustomView(View view)1148         public Tab setCustomView(View view) {
1149             mCustomView = view;
1150             if (mPosition >= 0) {
1151                 mTabScrollView.updateTab(mPosition);
1152             }
1153             return this;
1154         }
1155 
1156         @Override
setCustomView(int layoutResId)1157         public Tab setCustomView(int layoutResId) {
1158             return setCustomView(LayoutInflater.from(getThemedContext())
1159                     .inflate(layoutResId, null));
1160         }
1161 
1162         @Override
getIcon()1163         public Drawable getIcon() {
1164             return mIcon;
1165         }
1166 
1167         @Override
getPosition()1168         public int getPosition() {
1169             return mPosition;
1170         }
1171 
setPosition(int position)1172         public void setPosition(int position) {
1173             mPosition = position;
1174         }
1175 
1176         @Override
getText()1177         public CharSequence getText() {
1178             return mText;
1179         }
1180 
1181         @Override
setIcon(Drawable icon)1182         public Tab setIcon(Drawable icon) {
1183             mIcon = icon;
1184             if (mPosition >= 0) {
1185                 mTabScrollView.updateTab(mPosition);
1186             }
1187             return this;
1188         }
1189 
1190         @Override
setIcon(int resId)1191         public Tab setIcon(int resId) {
1192             return setIcon(getTintManager().getDrawable(resId));
1193         }
1194 
1195         @Override
setText(CharSequence text)1196         public Tab setText(CharSequence text) {
1197             mText = text;
1198             if (mPosition >= 0) {
1199                 mTabScrollView.updateTab(mPosition);
1200             }
1201             return this;
1202         }
1203 
1204         @Override
setText(int resId)1205         public Tab setText(int resId) {
1206             return setText(mContext.getResources().getText(resId));
1207         }
1208 
1209         @Override
select()1210         public void select() {
1211             selectTab(this);
1212         }
1213 
1214         @Override
setContentDescription(int resId)1215         public Tab setContentDescription(int resId) {
1216             return setContentDescription(mContext.getResources().getText(resId));
1217         }
1218 
1219         @Override
setContentDescription(CharSequence contentDesc)1220         public Tab setContentDescription(CharSequence contentDesc) {
1221             mContentDesc = contentDesc;
1222             if (mPosition >= 0) {
1223                 mTabScrollView.updateTab(mPosition);
1224             }
1225             return this;
1226         }
1227 
1228         @Override
getContentDescription()1229         public CharSequence getContentDescription() {
1230             return mContentDesc;
1231         }
1232     }
1233 
1234     @Override
setCustomView(View view)1235     public void setCustomView(View view) {
1236         mDecorToolbar.setCustomView(view);
1237     }
1238 
1239     @Override
setCustomView(View view, LayoutParams layoutParams)1240     public void setCustomView(View view, LayoutParams layoutParams) {
1241         view.setLayoutParams(layoutParams);
1242         mDecorToolbar.setCustomView(view);
1243     }
1244 
1245     @Override
setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback)1246     public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
1247         mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
1248     }
1249 
1250     @Override
getSelectedNavigationIndex()1251     public int getSelectedNavigationIndex() {
1252         switch (mDecorToolbar.getNavigationMode()) {
1253             case NAVIGATION_MODE_TABS:
1254                 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
1255             case NAVIGATION_MODE_LIST:
1256                 return mDecorToolbar.getDropdownSelectedPosition();
1257             default:
1258                 return -1;
1259         }
1260     }
1261 
1262     @Override
getNavigationItemCount()1263     public int getNavigationItemCount() {
1264         switch (mDecorToolbar.getNavigationMode()) {
1265             case NAVIGATION_MODE_TABS:
1266                 return mTabs.size();
1267             case NAVIGATION_MODE_LIST:
1268                 return mDecorToolbar.getDropdownItemCount();
1269             default:
1270                 return 0;
1271         }
1272     }
1273 
1274     @Override
getTabCount()1275     public int getTabCount() {
1276         return mTabs.size();
1277     }
1278 
1279     @Override
setNavigationMode(int mode)1280     public void setNavigationMode(int mode) {
1281         final int oldMode = mDecorToolbar.getNavigationMode();
1282         switch (oldMode) {
1283             case NAVIGATION_MODE_TABS:
1284                 mSavedTabPosition = getSelectedNavigationIndex();
1285                 selectTab(null);
1286                 mTabScrollView.setVisibility(View.GONE);
1287                 break;
1288         }
1289         if (oldMode != mode && !mHasEmbeddedTabs) {
1290             if (mOverlayLayout != null) {
1291                 ViewCompat.requestApplyInsets(mOverlayLayout);
1292             }
1293         }
1294         mDecorToolbar.setNavigationMode(mode);
1295         switch (mode) {
1296             case NAVIGATION_MODE_TABS:
1297                 ensureTabsExist();
1298                 mTabScrollView.setVisibility(View.VISIBLE);
1299                 if (mSavedTabPosition != INVALID_POSITION) {
1300                     setSelectedNavigationItem(mSavedTabPosition);
1301                     mSavedTabPosition = INVALID_POSITION;
1302                 }
1303                 break;
1304         }
1305         mDecorToolbar.setCollapsible(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
1306         mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
1307     }
1308 
1309     @Override
getTabAt(int index)1310     public Tab getTabAt(int index) {
1311         return mTabs.get(index);
1312     }
1313 
1314 
1315     @Override
setIcon(int resId)1316     public void setIcon(int resId) {
1317         mDecorToolbar.setIcon(resId);
1318     }
1319 
1320     @Override
setIcon(Drawable icon)1321     public void setIcon(Drawable icon) {
1322         mDecorToolbar.setIcon(icon);
1323     }
1324 
hasIcon()1325     public boolean hasIcon() {
1326         return mDecorToolbar.hasIcon();
1327     }
1328 
1329     @Override
setLogo(int resId)1330     public void setLogo(int resId) {
1331         mDecorToolbar.setLogo(resId);
1332     }
1333 
1334     @Override
setLogo(Drawable logo)1335     public void setLogo(Drawable logo) {
1336         mDecorToolbar.setLogo(logo);
1337     }
1338 
hasLogo()1339     public boolean hasLogo() {
1340         return mDecorToolbar.hasLogo();
1341     }
1342 
setDefaultDisplayHomeAsUpEnabled(boolean enable)1343     public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
1344         if (!mDisplayHomeAsUpSet) {
1345             setDisplayHomeAsUpEnabled(enable);
1346         }
1347     }
1348 
getTintManager()1349     TintManager getTintManager() {
1350         if (mTintManager == null) {
1351             mTintManager = new TintManager(mContext);
1352         }
1353         return mTintManager;
1354     }
1355 
1356 }
1357