1 /*
2  * Copyright (C) 2010 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 com.android.internal.app;
18 
19 import android.animation.Animator;
20 import android.animation.Animator.AnimatorListener;
21 import android.animation.AnimatorListenerAdapter;
22 import android.animation.AnimatorSet;
23 import android.animation.ObjectAnimator;
24 import android.animation.ValueAnimator;
25 import android.app.ActionBar;
26 import android.app.Activity;
27 import android.app.Dialog;
28 import android.app.FragmentTransaction;
29 import android.compat.annotation.UnsupportedAppUsage;
30 import android.content.Context;
31 import android.content.res.Configuration;
32 import android.content.res.Resources;
33 import android.content.res.TypedArray;
34 import android.graphics.drawable.Drawable;
35 import android.util.TypedValue;
36 import android.view.ActionMode;
37 import android.view.ContextThemeWrapper;
38 import android.view.LayoutInflater;
39 import android.view.Menu;
40 import android.view.MenuInflater;
41 import android.view.MenuItem;
42 import android.view.View;
43 import android.view.ViewParent;
44 import android.view.Window;
45 import android.view.accessibility.AccessibilityEvent;
46 import android.view.animation.AnimationUtils;
47 import android.widget.SpinnerAdapter;
48 import android.widget.Toolbar;
49 
50 import com.android.internal.R;
51 import com.android.internal.view.ActionBarPolicy;
52 import com.android.internal.view.menu.MenuBuilder;
53 import com.android.internal.view.menu.MenuPopupHelper;
54 import com.android.internal.view.menu.SubMenuBuilder;
55 import com.android.internal.widget.ActionBarContainer;
56 import com.android.internal.widget.ActionBarContextView;
57 import com.android.internal.widget.ActionBarOverlayLayout;
58 import com.android.internal.widget.DecorToolbar;
59 import com.android.internal.widget.ScrollingTabContainerView;
60 
61 import java.lang.ref.WeakReference;
62 import java.util.ArrayList;
63 
64 /**
65  * WindowDecorActionBar is the ActionBar implementation used
66  * by devices of all screen sizes as part of the window decor layout.
67  * If it detects a compatible decor, it will split contextual modes
68  * across both the ActionBarView at the top of the screen and
69  * a horizontal LinearLayout at the bottom which is normally hidden.
70  */
71 public class WindowDecorActionBar extends ActionBar implements
72         ActionBarOverlayLayout.ActionBarVisibilityCallback {
73     private static final String TAG = "WindowDecorActionBar";
74 
75     private Context mContext;
76     private Context mThemedContext;
77     private Activity mActivity;
78     private Dialog mDialog;
79 
80     private ActionBarOverlayLayout mOverlayLayout;
81     private ActionBarContainer mContainerView;
82     private DecorToolbar mDecorToolbar;
83     @UnsupportedAppUsage
84     private ActionBarContextView mContextView;
85     private ActionBarContainer mSplitView;
86     private View mContentView;
87     @UnsupportedAppUsage
88     private ScrollingTabContainerView mTabScrollView;
89 
90     private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
91 
92     private TabImpl mSelectedTab;
93     private int mSavedTabPosition = INVALID_POSITION;
94 
95     private boolean mDisplayHomeAsUpSet;
96 
97     ActionMode mActionMode;
98     ActionMode mDeferredDestroyActionMode;
99     ActionMode.Callback mDeferredModeDestroyCallback;
100 
101     private boolean mLastMenuVisibility;
102     private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
103             new ArrayList<OnMenuVisibilityListener>();
104 
105     private static final int CONTEXT_DISPLAY_NORMAL = 0;
106     private static final int CONTEXT_DISPLAY_SPLIT = 1;
107 
108     private static final int INVALID_POSITION = -1;
109 
110     // The fade duration for toolbar and action bar when entering/exiting action mode.
111     private static final long FADE_OUT_DURATION_MS = 100;
112     private static final long FADE_IN_DURATION_MS = 200;
113 
114     private int mContextDisplayMode;
115     private boolean mHasEmbeddedTabs;
116 
117     private int mCurWindowVisibility = View.VISIBLE;
118 
119     private boolean mContentAnimations = true;
120     private boolean mHiddenByApp;
121     private boolean mHiddenBySystem;
122     private boolean mShowingForMode;
123 
124     private boolean mNowShowing = true;
125 
126     private Animator mCurrentShowAnim;
127     private boolean mShowHideAnimationEnabled;
128     boolean mHideOnContentScroll;
129 
130     final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
131         @Override
132         public void onAnimationEnd(Animator animation) {
133             if (mContentAnimations && mContentView != null) {
134                 mContentView.setTranslationY(0);
135                 mContainerView.setTranslationY(0);
136             }
137             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
138                 mSplitView.setVisibility(View.GONE);
139             }
140             mContainerView.setVisibility(View.GONE);
141             mContainerView.setTransitioning(false);
142             mCurrentShowAnim = null;
143             completeDeferredDestroyActionMode();
144             if (mOverlayLayout != null) {
145                 mOverlayLayout.requestApplyInsets();
146             }
147         }
148     };
149 
150     final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
151         @Override
152         public void onAnimationEnd(Animator animation) {
153             mCurrentShowAnim = null;
154             mContainerView.requestLayout();
155         }
156     };
157 
158     final ValueAnimator.AnimatorUpdateListener mUpdateListener =
159             new ValueAnimator.AnimatorUpdateListener() {
160         @Override
161         public void onAnimationUpdate(ValueAnimator animation) {
162             final ViewParent parent = mContainerView.getParent();
163             ((View) parent).invalidate();
164         }
165     };
166 
WindowDecorActionBar(Activity activity)167     public WindowDecorActionBar(Activity activity) {
168         mActivity = activity;
169         Window window = activity.getWindow();
170         View decor = window.getDecorView();
171         boolean overlayMode = mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
172         init(decor);
173         if (!overlayMode) {
174             mContentView = decor.findViewById(android.R.id.content);
175         }
176     }
177 
WindowDecorActionBar(Dialog dialog)178     public WindowDecorActionBar(Dialog dialog) {
179         mDialog = dialog;
180         init(dialog.getWindow().getDecorView());
181     }
182 
183     /**
184      * Only for edit mode.
185      * @hide
186      */
WindowDecorActionBar(View layout)187     public WindowDecorActionBar(View layout) {
188         assert layout.isInEditMode();
189         init(layout);
190     }
191 
init(View decor)192     private void init(View decor) {
193         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
194                 com.android.internal.R.id.decor_content_parent);
195         if (mOverlayLayout != null) {
196             mOverlayLayout.setActionBarVisibilityCallback(this);
197         }
198         mDecorToolbar = getDecorToolbar(decor.findViewById(com.android.internal.R.id.action_bar));
199         mContextView = (ActionBarContextView) decor.findViewById(
200                 com.android.internal.R.id.action_context_bar);
201         mContainerView = (ActionBarContainer) decor.findViewById(
202                 com.android.internal.R.id.action_bar_container);
203         mSplitView = (ActionBarContainer) decor.findViewById(
204                 com.android.internal.R.id.split_action_bar);
205 
206         if (mDecorToolbar == null || mContextView == null || mContainerView == null) {
207             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
208                     "with a compatible window decor layout");
209         }
210 
211         mContext = mDecorToolbar.getContext();
212         mContextDisplayMode = mDecorToolbar.isSplit() ?
213                 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
214 
215         // This was initially read from the action bar style
216         final int current = mDecorToolbar.getDisplayOptions();
217         final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
218         if (homeAsUp) {
219             mDisplayHomeAsUpSet = true;
220         }
221 
222         ActionBarPolicy abp = ActionBarPolicy.get(mContext);
223         setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp);
224         setHasEmbeddedTabs(abp.hasEmbeddedTabs());
225 
226         final TypedArray a = mContext.obtainStyledAttributes(null,
227                 com.android.internal.R.styleable.ActionBar,
228                 com.android.internal.R.attr.actionBarStyle, 0);
229         if (a.getBoolean(R.styleable.ActionBar_hideOnContentScroll, false)) {
230             setHideOnContentScrollEnabled(true);
231         }
232         final int elevation = a.getDimensionPixelSize(R.styleable.ActionBar_elevation, 0);
233         if (elevation != 0) {
234             setElevation(elevation);
235         }
236         a.recycle();
237     }
238 
getDecorToolbar(View view)239     private DecorToolbar getDecorToolbar(View view) {
240         if (view instanceof DecorToolbar) {
241             return (DecorToolbar) view;
242         } else if (view instanceof Toolbar) {
243             return ((Toolbar) view).getWrapper();
244         } else {
245             throw new IllegalStateException("Can't make a decor toolbar out of " +
246                     view.getClass().getSimpleName());
247         }
248     }
249 
250     @Override
setElevation(float elevation)251     public void setElevation(float elevation) {
252         mContainerView.setElevation(elevation);
253         if (mSplitView != null) {
254             mSplitView.setElevation(elevation);
255         }
256     }
257 
258     @Override
getElevation()259     public float getElevation() {
260         return mContainerView.getElevation();
261     }
262 
onConfigurationChanged(Configuration newConfig)263     public void onConfigurationChanged(Configuration newConfig) {
264         setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
265     }
266 
setHasEmbeddedTabs(boolean hasEmbeddedTabs)267     private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) {
268         mHasEmbeddedTabs = hasEmbeddedTabs;
269         // Switch tab layout configuration if needed
270         if (!mHasEmbeddedTabs) {
271             mDecorToolbar.setEmbeddedTabView(null);
272             mContainerView.setTabContainer(mTabScrollView);
273         } else {
274             mContainerView.setTabContainer(null);
275             mDecorToolbar.setEmbeddedTabView(mTabScrollView);
276         }
277         final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
278         if (mTabScrollView != null) {
279             if (isInTabMode) {
280                 mTabScrollView.setVisibility(View.VISIBLE);
281                 if (mOverlayLayout != null) {
282                     mOverlayLayout.requestApplyInsets();
283                 }
284             } else {
285                 mTabScrollView.setVisibility(View.GONE);
286             }
287         }
288         mDecorToolbar.setCollapsible(!mHasEmbeddedTabs && isInTabMode);
289         mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
290     }
291 
ensureTabsExist()292     private void ensureTabsExist() {
293         if (mTabScrollView != null) {
294             return;
295         }
296 
297         ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext);
298 
299         if (mHasEmbeddedTabs) {
300             tabScroller.setVisibility(View.VISIBLE);
301             mDecorToolbar.setEmbeddedTabView(tabScroller);
302         } else {
303             if (getNavigationMode() == NAVIGATION_MODE_TABS) {
304                 tabScroller.setVisibility(View.VISIBLE);
305                 if (mOverlayLayout != null) {
306                     mOverlayLayout.requestApplyInsets();
307                 }
308             } else {
309                 tabScroller.setVisibility(View.GONE);
310             }
311             mContainerView.setTabContainer(tabScroller);
312         }
313         mTabScrollView = tabScroller;
314     }
315 
completeDeferredDestroyActionMode()316     void completeDeferredDestroyActionMode() {
317         if (mDeferredModeDestroyCallback != null) {
318             mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
319             mDeferredDestroyActionMode = null;
320             mDeferredModeDestroyCallback = null;
321         }
322     }
323 
onWindowVisibilityChanged(int visibility)324     public void onWindowVisibilityChanged(int visibility) {
325         mCurWindowVisibility = visibility;
326     }
327 
328     /**
329      * Enables or disables animation between show/hide states.
330      * If animation is disabled using this method, animations in progress
331      * will be finished.
332      *
333      * @param enabled true to animate, false to not animate.
334      */
335     @UnsupportedAppUsage
setShowHideAnimationEnabled(boolean enabled)336     public void setShowHideAnimationEnabled(boolean enabled) {
337         mShowHideAnimationEnabled = enabled;
338         if (!enabled && mCurrentShowAnim != null) {
339             mCurrentShowAnim.end();
340         }
341     }
342 
addOnMenuVisibilityListener(OnMenuVisibilityListener listener)343     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
344         mMenuVisibilityListeners.add(listener);
345     }
346 
removeOnMenuVisibilityListener(OnMenuVisibilityListener listener)347     public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
348         mMenuVisibilityListeners.remove(listener);
349     }
350 
dispatchMenuVisibilityChanged(boolean isVisible)351     public void dispatchMenuVisibilityChanged(boolean isVisible) {
352         if (isVisible == mLastMenuVisibility) {
353             return;
354         }
355         mLastMenuVisibility = isVisible;
356 
357         final int count = mMenuVisibilityListeners.size();
358         for (int i = 0; i < count; i++) {
359             mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
360         }
361     }
362 
363     @Override
setCustomView(int resId)364     public void setCustomView(int resId) {
365         setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId,
366                 mDecorToolbar.getViewGroup(), false));
367     }
368 
369     @Override
setDisplayUseLogoEnabled(boolean useLogo)370     public void setDisplayUseLogoEnabled(boolean useLogo) {
371         setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
372     }
373 
374     @Override
setDisplayShowHomeEnabled(boolean showHome)375     public void setDisplayShowHomeEnabled(boolean showHome) {
376         setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
377     }
378 
379     @Override
setDisplayHomeAsUpEnabled(boolean showHomeAsUp)380     public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
381         setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
382     }
383 
384     @Override
setDisplayShowTitleEnabled(boolean showTitle)385     public void setDisplayShowTitleEnabled(boolean showTitle) {
386         setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
387     }
388 
389     @Override
setDisplayShowCustomEnabled(boolean showCustom)390     public void setDisplayShowCustomEnabled(boolean showCustom) {
391         setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
392     }
393 
394     @Override
setHomeButtonEnabled(boolean enable)395     public void setHomeButtonEnabled(boolean enable) {
396         mDecorToolbar.setHomeButtonEnabled(enable);
397     }
398 
399     @Override
setTitle(int resId)400     public void setTitle(int resId) {
401         setTitle(mContext.getString(resId));
402     }
403 
404     @Override
setSubtitle(int resId)405     public void setSubtitle(int resId) {
406         setSubtitle(mContext.getString(resId));
407     }
408 
setSelectedNavigationItem(int position)409     public void setSelectedNavigationItem(int position) {
410         switch (mDecorToolbar.getNavigationMode()) {
411         case NAVIGATION_MODE_TABS:
412             selectTab(mTabs.get(position));
413             break;
414         case NAVIGATION_MODE_LIST:
415             mDecorToolbar.setDropdownSelectedPosition(position);
416             break;
417         default:
418             throw new IllegalStateException(
419                     "setSelectedNavigationIndex not valid for current navigation mode");
420         }
421     }
422 
removeAllTabs()423     public void removeAllTabs() {
424         cleanupTabs();
425     }
426 
cleanupTabs()427     private void cleanupTabs() {
428         if (mSelectedTab != null) {
429             selectTab(null);
430         }
431         mTabs.clear();
432         if (mTabScrollView != null) {
433             mTabScrollView.removeAllTabs();
434         }
435         mSavedTabPosition = INVALID_POSITION;
436     }
437 
setTitle(CharSequence title)438     public void setTitle(CharSequence title) {
439         mDecorToolbar.setTitle(title);
440     }
441 
442     @Override
setWindowTitle(CharSequence title)443     public void setWindowTitle(CharSequence title) {
444         mDecorToolbar.setWindowTitle(title);
445     }
446 
setSubtitle(CharSequence subtitle)447     public void setSubtitle(CharSequence subtitle) {
448         mDecorToolbar.setSubtitle(subtitle);
449     }
450 
setDisplayOptions(int options)451     public void setDisplayOptions(int options) {
452         if ((options & DISPLAY_HOME_AS_UP) != 0) {
453             mDisplayHomeAsUpSet = true;
454         }
455         mDecorToolbar.setDisplayOptions(options);
456     }
457 
setDisplayOptions(int options, int mask)458     public void setDisplayOptions(int options, int mask) {
459         final int current = mDecorToolbar.getDisplayOptions();
460         if ((mask & DISPLAY_HOME_AS_UP) != 0) {
461             mDisplayHomeAsUpSet = true;
462         }
463         mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask));
464     }
465 
setBackgroundDrawable(Drawable d)466     public void setBackgroundDrawable(Drawable d) {
467         mContainerView.setPrimaryBackground(d);
468     }
469 
setStackedBackgroundDrawable(Drawable d)470     public void setStackedBackgroundDrawable(Drawable d) {
471         mContainerView.setStackedBackground(d);
472     }
473 
setSplitBackgroundDrawable(Drawable d)474     public void setSplitBackgroundDrawable(Drawable d) {
475         if (mSplitView != null) {
476             mSplitView.setSplitBackground(d);
477         }
478     }
479 
getCustomView()480     public View getCustomView() {
481         return mDecorToolbar.getCustomView();
482     }
483 
getTitle()484     public CharSequence getTitle() {
485         return mDecorToolbar.getTitle();
486     }
487 
getSubtitle()488     public CharSequence getSubtitle() {
489         return mDecorToolbar.getSubtitle();
490     }
491 
getNavigationMode()492     public int getNavigationMode() {
493         return mDecorToolbar.getNavigationMode();
494     }
495 
getDisplayOptions()496     public int getDisplayOptions() {
497         return mDecorToolbar.getDisplayOptions();
498     }
499 
startActionMode(ActionMode.Callback callback)500     public ActionMode startActionMode(ActionMode.Callback callback) {
501         if (mActionMode != null) {
502             mActionMode.finish();
503         }
504 
505         mOverlayLayout.setHideOnContentScrollEnabled(false);
506         mContextView.killMode();
507         ActionModeImpl mode = new ActionModeImpl(mContextView.getContext(), callback);
508         if (mode.dispatchOnCreate()) {
509             // This needs to be set before invalidate() so that it calls
510             // onPrepareActionMode()
511             mActionMode = mode;
512             mode.invalidate();
513             mContextView.initForMode(mode);
514             animateToMode(true);
515             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
516                 // TODO animate this
517                 if (mSplitView.getVisibility() != View.VISIBLE) {
518                     mSplitView.setVisibility(View.VISIBLE);
519                     if (mOverlayLayout != null) {
520                         mOverlayLayout.requestApplyInsets();
521                     }
522                 }
523             }
524             mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
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.getFragmentManager().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.end();
768         }
769         mContainerView.setVisibility(View.VISIBLE);
770 
771         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
772                 || fromSystem)) {
773             mContainerView.setTranslationY(0); // because we're about to ask its window loc
774             float startingY = -mContainerView.getHeight();
775             if (fromSystem) {
776                 int topLeft[] = {0, 0};
777                 mContainerView.getLocationInWindow(topLeft);
778                 startingY -= topLeft[1];
779             }
780             mContainerView.setTranslationY(startingY);
781             AnimatorSet anim = new AnimatorSet();
782             ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, 0);
783             a.addUpdateListener(mUpdateListener);
784             AnimatorSet.Builder b = anim.play(a);
785             if (mContentAnimations && mContentView != null) {
786                 b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
787                         startingY, 0));
788             }
789             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
790                 mSplitView.setTranslationY(mSplitView.getHeight());
791                 mSplitView.setVisibility(View.VISIBLE);
792                 b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y, 0));
793             }
794             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
795                     com.android.internal.R.interpolator.decelerate_cubic));
796             anim.setDuration(250);
797             // If this is being shown from the system, add a small delay.
798             // This is because we will also be animating in the status bar,
799             // and these two elements can't be done in lock-step.  So we give
800             // a little time for the status bar to start its animation before
801             // the action bar animates.  (This corresponds to the corresponding
802             // case when hiding, where the status bar has a small delay before
803             // starting.)
804             anim.addListener(mShowListener);
805             mCurrentShowAnim = anim;
806             anim.start();
807         } else {
808             mContainerView.setAlpha(1);
809             mContainerView.setTranslationY(0);
810             if (mContentAnimations && mContentView != null) {
811                 mContentView.setTranslationY(0);
812             }
813             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
814                 mSplitView.setAlpha(1);
815                 mSplitView.setTranslationY(0);
816                 mSplitView.setVisibility(View.VISIBLE);
817             }
818             mShowListener.onAnimationEnd(null);
819         }
820         if (mOverlayLayout != null) {
821             mOverlayLayout.requestApplyInsets();
822         }
823     }
824 
doHide(boolean fromSystem)825     public void doHide(boolean fromSystem) {
826         if (mCurrentShowAnim != null) {
827             mCurrentShowAnim.end();
828         }
829 
830         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
831                 || fromSystem)) {
832             mContainerView.setAlpha(1);
833             mContainerView.setTransitioning(true);
834             AnimatorSet anim = new AnimatorSet();
835             float endingY = -mContainerView.getHeight();
836             if (fromSystem) {
837                 int topLeft[] = {0, 0};
838                 mContainerView.getLocationInWindow(topLeft);
839                 endingY -= topLeft[1];
840             }
841             ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, endingY);
842             a.addUpdateListener(mUpdateListener);
843             AnimatorSet.Builder b = anim.play(a);
844             if (mContentAnimations && mContentView != null) {
845                 b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
846                         0, endingY));
847             }
848             if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
849                 mSplitView.setAlpha(1);
850                 b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y,
851                         mSplitView.getHeight()));
852             }
853             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
854                     com.android.internal.R.interpolator.accelerate_cubic));
855             anim.setDuration(250);
856             anim.addListener(mHideListener);
857             mCurrentShowAnim = anim;
858             anim.start();
859         } else {
860             mHideListener.onAnimationEnd(null);
861         }
862     }
863 
isShowing()864     public boolean isShowing() {
865         final int height = getHeight();
866         // Take into account the case where the bar has a 0 height due to not being measured yet.
867         return mNowShowing && (height == 0 || getHideOffset() < height);
868     }
869 
animateToMode(boolean toActionMode)870     void animateToMode(boolean toActionMode) {
871         if (toActionMode) {
872             showForActionMode();
873         } else {
874             hideForActionMode();
875         }
876 
877         if (shouldAnimateContextView()) {
878             Animator fadeIn, fadeOut;
879             if (toActionMode) {
880                 fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE,
881                         FADE_OUT_DURATION_MS);
882                 fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE,
883                         FADE_IN_DURATION_MS);
884             } else {
885                 fadeIn = mDecorToolbar.setupAnimatorToVisibility(View.VISIBLE,
886                         FADE_IN_DURATION_MS);
887                 fadeOut = mContextView.setupAnimatorToVisibility(View.GONE,
888                         FADE_OUT_DURATION_MS);
889             }
890             AnimatorSet set = new AnimatorSet();
891             set.playSequentially(fadeOut, fadeIn);
892             set.start();
893         } else {
894             if (toActionMode) {
895                 mDecorToolbar.setVisibility(View.GONE);
896                 mContextView.setVisibility(View.VISIBLE);
897             } else {
898                 mDecorToolbar.setVisibility(View.VISIBLE);
899                 mContextView.setVisibility(View.GONE);
900             }
901         }
902         // mTabScrollView's visibility is not affected by action mode.
903     }
904 
shouldAnimateContextView()905     private boolean shouldAnimateContextView() {
906         // We only to animate the action mode in if the container view has already been laid out.
907         // If it hasn't been laid out, it hasn't been drawn to screen yet.
908         return mContainerView.isLaidOut();
909     }
910 
getThemedContext()911     public Context getThemedContext() {
912         if (mThemedContext == null) {
913             TypedValue outValue = new TypedValue();
914             Resources.Theme currentTheme = mContext.getTheme();
915             currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
916                     outValue, true);
917             final int targetThemeRes = outValue.resourceId;
918 
919             if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) {
920                 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
921             } else {
922                 mThemedContext = mContext;
923             }
924         }
925         return mThemedContext;
926     }
927 
928     @Override
isTitleTruncated()929     public boolean isTitleTruncated() {
930         return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
931     }
932 
933     @Override
setHomeAsUpIndicator(Drawable indicator)934     public void setHomeAsUpIndicator(Drawable indicator) {
935         mDecorToolbar.setNavigationIcon(indicator);
936     }
937 
938     @Override
setHomeAsUpIndicator(int resId)939     public void setHomeAsUpIndicator(int resId) {
940         mDecorToolbar.setNavigationIcon(resId);
941     }
942 
943     @Override
setHomeActionContentDescription(CharSequence description)944     public void setHomeActionContentDescription(CharSequence description) {
945         mDecorToolbar.setNavigationContentDescription(description);
946     }
947 
948     @Override
setHomeActionContentDescription(int resId)949     public void setHomeActionContentDescription(int resId) {
950         mDecorToolbar.setNavigationContentDescription(resId);
951     }
952 
953     @Override
onContentScrollStarted()954     public void onContentScrollStarted() {
955         if (mCurrentShowAnim != null) {
956             mCurrentShowAnim.cancel();
957             mCurrentShowAnim = null;
958         }
959     }
960 
961     @Override
onContentScrollStopped()962     public void onContentScrollStopped() {
963     }
964 
965     @Override
collapseActionView()966     public boolean collapseActionView() {
967         if (mDecorToolbar != null && mDecorToolbar.hasExpandedActionView()) {
968             mDecorToolbar.collapseActionView();
969             return true;
970         }
971         return false;
972     }
973 
974     /**
975      * @hide
976      */
977     public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
978         private final Context mActionModeContext;
979         private final MenuBuilder mMenu;
980 
981         private ActionMode.Callback mCallback;
982         private WeakReference<View> mCustomView;
983 
ActionModeImpl( Context context, ActionMode.Callback callback)984         public ActionModeImpl(
985                 Context context, ActionMode.Callback callback) {
986             mActionModeContext = context;
987             mCallback = callback;
988             mMenu = new MenuBuilder(context)
989                         .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
990             mMenu.setCallback(this);
991         }
992 
993         @Override
getMenuInflater()994         public MenuInflater getMenuInflater() {
995             return new MenuInflater(mActionModeContext);
996         }
997 
998         @Override
getMenu()999         public Menu getMenu() {
1000             return mMenu;
1001         }
1002 
1003         @Override
finish()1004         public void finish() {
1005             if (mActionMode != this) {
1006                 // Not the active action mode - no-op
1007                 return;
1008             }
1009 
1010             // If this change in state is going to cause the action bar
1011             // to be hidden, defer the onDestroy callback until the animation
1012             // is finished and associated relayout is about to happen. This lets
1013             // apps better anticipate visibility and layout behavior.
1014             if (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) {
1015                 // With the current state but the action bar hidden, our
1016                 // overall showing state is going to be false.
1017                 mDeferredDestroyActionMode = this;
1018                 mDeferredModeDestroyCallback = mCallback;
1019             } else {
1020                 mCallback.onDestroyActionMode(this);
1021             }
1022             mCallback = null;
1023             animateToMode(false);
1024 
1025             // Clear out the context mode views after the animation finishes
1026             mContextView.closeMode();
1027             mDecorToolbar.getViewGroup().sendAccessibilityEvent(
1028                     AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
1029             mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
1030 
1031             mActionMode = null;
1032         }
1033 
1034         @Override
invalidate()1035         public void invalidate() {
1036             if (mActionMode != this) {
1037                 // Not the active action mode - no-op. It's possible we are
1038                 // currently deferring onDestroy, so the app doesn't yet know we
1039                 // are going away and is trying to use us. That's also a no-op.
1040                 return;
1041             }
1042 
1043             mMenu.stopDispatchingItemsChanged();
1044             try {
1045                 mCallback.onPrepareActionMode(this, mMenu);
1046             } finally {
1047                 mMenu.startDispatchingItemsChanged();
1048             }
1049         }
1050 
dispatchOnCreate()1051         public boolean dispatchOnCreate() {
1052             mMenu.stopDispatchingItemsChanged();
1053             try {
1054                 return mCallback.onCreateActionMode(this, mMenu);
1055             } finally {
1056                 mMenu.startDispatchingItemsChanged();
1057             }
1058         }
1059 
1060         @Override
setCustomView(View view)1061         public void setCustomView(View view) {
1062             mContextView.setCustomView(view);
1063             mCustomView = new WeakReference<View>(view);
1064         }
1065 
1066         @Override
setSubtitle(CharSequence subtitle)1067         public void setSubtitle(CharSequence subtitle) {
1068             mContextView.setSubtitle(subtitle);
1069         }
1070 
1071         @Override
setTitle(CharSequence title)1072         public void setTitle(CharSequence title) {
1073             mContextView.setTitle(title);
1074         }
1075 
1076         @Override
setTitle(int resId)1077         public void setTitle(int resId) {
1078             setTitle(mContext.getResources().getString(resId));
1079         }
1080 
1081         @Override
setSubtitle(int resId)1082         public void setSubtitle(int resId) {
1083             setSubtitle(mContext.getResources().getString(resId));
1084         }
1085 
1086         @Override
getTitle()1087         public CharSequence getTitle() {
1088             return mContextView.getTitle();
1089         }
1090 
1091         @Override
getSubtitle()1092         public CharSequence getSubtitle() {
1093             return mContextView.getSubtitle();
1094         }
1095 
1096         @Override
setTitleOptionalHint(boolean titleOptional)1097         public void setTitleOptionalHint(boolean titleOptional) {
1098             super.setTitleOptionalHint(titleOptional);
1099             mContextView.setTitleOptional(titleOptional);
1100         }
1101 
1102         @Override
isTitleOptional()1103         public boolean isTitleOptional() {
1104             return mContextView.isTitleOptional();
1105         }
1106 
1107         @Override
getCustomView()1108         public View getCustomView() {
1109             return mCustomView != null ? mCustomView.get() : null;
1110         }
1111 
onMenuItemSelected(MenuBuilder menu, MenuItem item)1112         public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
1113             if (mCallback != null) {
1114                 return mCallback.onActionItemClicked(this, item);
1115             } else {
1116                 return false;
1117             }
1118         }
1119 
onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing)1120         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
1121         }
1122 
onSubMenuSelected(SubMenuBuilder subMenu)1123         public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
1124             if (mCallback == null) {
1125                 return false;
1126             }
1127 
1128             if (!subMenu.hasVisibleItems()) {
1129                 return true;
1130             }
1131 
1132             new MenuPopupHelper(getThemedContext(), subMenu).show();
1133             return true;
1134         }
1135 
onCloseSubMenu(SubMenuBuilder menu)1136         public void onCloseSubMenu(SubMenuBuilder menu) {
1137         }
1138 
onMenuModeChange(MenuBuilder menu)1139         public void onMenuModeChange(MenuBuilder menu) {
1140             if (mCallback == null) {
1141                 return;
1142             }
1143             invalidate();
1144             mContextView.showOverflowMenu();
1145         }
1146     }
1147 
1148     /**
1149      * @hide
1150      */
1151     public class TabImpl extends ActionBar.Tab {
1152         @UnsupportedAppUsage
1153         private ActionBar.TabListener mCallback;
1154         private Object mTag;
1155         private Drawable mIcon;
1156         private CharSequence mText;
1157         private CharSequence mContentDesc;
1158         private int mPosition = -1;
1159         private View mCustomView;
1160 
1161         @Override
getTag()1162         public Object getTag() {
1163             return mTag;
1164         }
1165 
1166         @Override
setTag(Object tag)1167         public Tab setTag(Object tag) {
1168             mTag = tag;
1169             return this;
1170         }
1171 
getCallback()1172         public ActionBar.TabListener getCallback() {
1173             return mCallback;
1174         }
1175 
1176         @Override
setTabListener(ActionBar.TabListener callback)1177         public Tab setTabListener(ActionBar.TabListener callback) {
1178             mCallback = callback;
1179             return this;
1180         }
1181 
1182         @Override
getCustomView()1183         public View getCustomView() {
1184             return mCustomView;
1185         }
1186 
1187         @Override
setCustomView(View view)1188         public Tab setCustomView(View view) {
1189             mCustomView = view;
1190             if (mPosition >= 0) {
1191                 mTabScrollView.updateTab(mPosition);
1192             }
1193             return this;
1194         }
1195 
1196         @Override
setCustomView(int layoutResId)1197         public Tab setCustomView(int layoutResId) {
1198             return setCustomView(LayoutInflater.from(getThemedContext())
1199                     .inflate(layoutResId, null));
1200         }
1201 
1202         @Override
getIcon()1203         public Drawable getIcon() {
1204             return mIcon;
1205         }
1206 
1207         @Override
getPosition()1208         public int getPosition() {
1209             return mPosition;
1210         }
1211 
setPosition(int position)1212         public void setPosition(int position) {
1213             mPosition = position;
1214         }
1215 
1216         @Override
getText()1217         public CharSequence getText() {
1218             return mText;
1219         }
1220 
1221         @Override
setIcon(Drawable icon)1222         public Tab setIcon(Drawable icon) {
1223             mIcon = icon;
1224             if (mPosition >= 0) {
1225                 mTabScrollView.updateTab(mPosition);
1226             }
1227             return this;
1228         }
1229 
1230         @Override
setIcon(int resId)1231         public Tab setIcon(int resId) {
1232             return setIcon(mContext.getDrawable(resId));
1233         }
1234 
1235         @Override
setText(CharSequence text)1236         public Tab setText(CharSequence text) {
1237             mText = text;
1238             if (mPosition >= 0) {
1239                 mTabScrollView.updateTab(mPosition);
1240             }
1241             return this;
1242         }
1243 
1244         @Override
setText(int resId)1245         public Tab setText(int resId) {
1246             return setText(mContext.getResources().getText(resId));
1247         }
1248 
1249         @Override
select()1250         public void select() {
1251             selectTab(this);
1252         }
1253 
1254         @Override
setContentDescription(int resId)1255         public Tab setContentDescription(int resId) {
1256             return setContentDescription(mContext.getResources().getText(resId));
1257         }
1258 
1259         @Override
setContentDescription(CharSequence contentDesc)1260         public Tab setContentDescription(CharSequence contentDesc) {
1261             mContentDesc = contentDesc;
1262             if (mPosition >= 0) {
1263                 mTabScrollView.updateTab(mPosition);
1264             }
1265             return this;
1266         }
1267 
1268         @Override
getContentDescription()1269         public CharSequence getContentDescription() {
1270             return mContentDesc;
1271         }
1272     }
1273 
1274     @Override
setCustomView(View view)1275     public void setCustomView(View view) {
1276         mDecorToolbar.setCustomView(view);
1277     }
1278 
1279     @Override
setCustomView(View view, LayoutParams layoutParams)1280     public void setCustomView(View view, LayoutParams layoutParams) {
1281         view.setLayoutParams(layoutParams);
1282         mDecorToolbar.setCustomView(view);
1283     }
1284 
1285     @Override
setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback)1286     public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
1287         mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
1288     }
1289 
1290     @Override
getSelectedNavigationIndex()1291     public int getSelectedNavigationIndex() {
1292         switch (mDecorToolbar.getNavigationMode()) {
1293             case NAVIGATION_MODE_TABS:
1294                 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
1295             case NAVIGATION_MODE_LIST:
1296                 return mDecorToolbar.getDropdownSelectedPosition();
1297             default:
1298                 return -1;
1299         }
1300     }
1301 
1302     @Override
getNavigationItemCount()1303     public int getNavigationItemCount() {
1304         switch (mDecorToolbar.getNavigationMode()) {
1305             case NAVIGATION_MODE_TABS:
1306                 return mTabs.size();
1307             case NAVIGATION_MODE_LIST:
1308                 return mDecorToolbar.getDropdownItemCount();
1309             default:
1310                 return 0;
1311         }
1312     }
1313 
1314     @Override
getTabCount()1315     public int getTabCount() {
1316         return mTabs.size();
1317     }
1318 
1319     @Override
setNavigationMode(int mode)1320     public void setNavigationMode(int mode) {
1321         final int oldMode = mDecorToolbar.getNavigationMode();
1322         switch (oldMode) {
1323             case NAVIGATION_MODE_TABS:
1324                 mSavedTabPosition = getSelectedNavigationIndex();
1325                 selectTab(null);
1326                 mTabScrollView.setVisibility(View.GONE);
1327                 break;
1328         }
1329         if (oldMode != mode && !mHasEmbeddedTabs) {
1330             if (mOverlayLayout != null) {
1331                 mOverlayLayout.requestFitSystemWindows();
1332             }
1333         }
1334         mDecorToolbar.setNavigationMode(mode);
1335         switch (mode) {
1336             case NAVIGATION_MODE_TABS:
1337                 ensureTabsExist();
1338                 mTabScrollView.setVisibility(View.VISIBLE);
1339                 if (mSavedTabPosition != INVALID_POSITION) {
1340                     setSelectedNavigationItem(mSavedTabPosition);
1341                     mSavedTabPosition = INVALID_POSITION;
1342                 }
1343                 break;
1344         }
1345         mDecorToolbar.setCollapsible(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
1346         mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
1347     }
1348 
1349     @Override
getTabAt(int index)1350     public Tab getTabAt(int index) {
1351         return mTabs.get(index);
1352     }
1353 
1354 
1355     @Override
setIcon(int resId)1356     public void setIcon(int resId) {
1357         mDecorToolbar.setIcon(resId);
1358     }
1359 
1360     @Override
setIcon(Drawable icon)1361     public void setIcon(Drawable icon) {
1362         mDecorToolbar.setIcon(icon);
1363     }
1364 
hasIcon()1365     public boolean hasIcon() {
1366         return mDecorToolbar.hasIcon();
1367     }
1368 
1369     @Override
setLogo(int resId)1370     public void setLogo(int resId) {
1371         mDecorToolbar.setLogo(resId);
1372     }
1373 
1374     @Override
setLogo(Drawable logo)1375     public void setLogo(Drawable logo) {
1376         mDecorToolbar.setLogo(logo);
1377     }
1378 
hasLogo()1379     public boolean hasLogo() {
1380         return mDecorToolbar.hasLogo();
1381     }
1382 
setDefaultDisplayHomeAsUpEnabled(boolean enable)1383     public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
1384         if (!mDisplayHomeAsUpSet) {
1385             setDisplayHomeAsUpEnabled(enable);
1386         }
1387     }
1388 
1389 }
1390