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