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