Home | History | Annotate | Download | only in widget
      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.widget;
     18 
     19 import com.android.internal.R;
     20 import com.android.internal.view.menu.ActionMenuItem;
     21 import com.android.internal.view.menu.ActionMenuPresenter;
     22 import com.android.internal.view.menu.ActionMenuView;
     23 import com.android.internal.view.menu.MenuBuilder;
     24 import com.android.internal.view.menu.MenuItemImpl;
     25 import com.android.internal.view.menu.MenuPresenter;
     26 import com.android.internal.view.menu.MenuView;
     27 import com.android.internal.view.menu.SubMenuBuilder;
     28 
     29 import android.app.ActionBar;
     30 import android.app.ActionBar.OnNavigationListener;
     31 import android.app.Activity;
     32 import android.content.Context;
     33 import android.content.pm.ApplicationInfo;
     34 import android.content.pm.PackageManager;
     35 import android.content.pm.PackageManager.NameNotFoundException;
     36 import android.content.res.Configuration;
     37 import android.content.res.TypedArray;
     38 import android.graphics.drawable.Drawable;
     39 import android.os.Parcel;
     40 import android.os.Parcelable;
     41 import android.text.TextUtils;
     42 import android.util.AttributeSet;
     43 import android.util.Log;
     44 import android.view.CollapsibleActionView;
     45 import android.view.Gravity;
     46 import android.view.LayoutInflater;
     47 import android.view.Menu;
     48 import android.view.MenuItem;
     49 import android.view.MotionEvent;
     50 import android.view.View;
     51 import android.view.ViewGroup;
     52 import android.view.ViewParent;
     53 import android.view.Window;
     54 import android.view.accessibility.AccessibilityEvent;
     55 import android.widget.AdapterView;
     56 import android.widget.FrameLayout;
     57 import android.widget.ImageView;
     58 import android.widget.LinearLayout;
     59 import android.widget.ProgressBar;
     60 import android.widget.Spinner;
     61 import android.widget.SpinnerAdapter;
     62 import android.widget.TextView;
     63 
     64 /**
     65  * @hide
     66  */
     67 public class ActionBarView extends AbsActionBarView {
     68     private static final String TAG = "ActionBarView";
     69 
     70     /**
     71      * Display options applied by default
     72      */
     73     public static final int DISPLAY_DEFAULT = 0;
     74 
     75     /**
     76      * Display options that require re-layout as opposed to a simple invalidate
     77      */
     78     private static final int DISPLAY_RELAYOUT_MASK =
     79             ActionBar.DISPLAY_SHOW_HOME |
     80             ActionBar.DISPLAY_USE_LOGO |
     81             ActionBar.DISPLAY_HOME_AS_UP |
     82             ActionBar.DISPLAY_SHOW_CUSTOM |
     83             ActionBar.DISPLAY_SHOW_TITLE;
     84 
     85     private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL;
     86 
     87     private int mNavigationMode;
     88     private int mDisplayOptions = -1;
     89     private CharSequence mTitle;
     90     private CharSequence mSubtitle;
     91     private Drawable mIcon;
     92     private Drawable mLogo;
     93 
     94     private HomeView mHomeLayout;
     95     private HomeView mExpandedHomeLayout;
     96     private LinearLayout mTitleLayout;
     97     private TextView mTitleView;
     98     private TextView mSubtitleView;
     99     private View mTitleUpView;
    100 
    101     private Spinner mSpinner;
    102     private LinearLayout mListNavLayout;
    103     private ScrollingTabContainerView mTabScrollView;
    104     private View mCustomNavView;
    105     private ProgressBar mProgressView;
    106     private ProgressBar mIndeterminateProgressView;
    107 
    108     private int mProgressBarPadding;
    109     private int mItemPadding;
    110 
    111     private int mTitleStyleRes;
    112     private int mSubtitleStyleRes;
    113     private int mProgressStyle;
    114     private int mIndeterminateProgressStyle;
    115 
    116     private boolean mUserTitle;
    117     private boolean mIncludeTabs;
    118     private boolean mIsCollapsable;
    119     private boolean mIsCollapsed;
    120 
    121     private MenuBuilder mOptionsMenu;
    122 
    123     private ActionBarContextView mContextView;
    124 
    125     private ActionMenuItem mLogoNavItem;
    126 
    127     private SpinnerAdapter mSpinnerAdapter;
    128     private OnNavigationListener mCallback;
    129 
    130     private Runnable mTabSelector;
    131 
    132     private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
    133     View mExpandedActionView;
    134 
    135     Window.Callback mWindowCallback;
    136 
    137     private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
    138             new AdapterView.OnItemSelectedListener() {
    139         public void onItemSelected(AdapterView parent, View view, int position, long id) {
    140             if (mCallback != null) {
    141                 mCallback.onNavigationItemSelected(position, id);
    142             }
    143         }
    144         public void onNothingSelected(AdapterView parent) {
    145             // Do nothing
    146         }
    147     };
    148 
    149     private final OnClickListener mExpandedActionViewUpListener = new OnClickListener() {
    150         @Override
    151         public void onClick(View v) {
    152             final MenuItemImpl item = mExpandedMenuPresenter.mCurrentExpandedItem;
    153             if (item != null) {
    154                 item.collapseActionView();
    155             }
    156         }
    157     };
    158 
    159     private final OnClickListener mUpClickListener = new OnClickListener() {
    160         public void onClick(View v) {
    161             mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
    162         }
    163     };
    164 
    165     public ActionBarView(Context context, AttributeSet attrs) {
    166         super(context, attrs);
    167 
    168         // Background is always provided by the container.
    169         setBackgroundResource(0);
    170 
    171         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar,
    172                 com.android.internal.R.attr.actionBarStyle, 0);
    173 
    174         ApplicationInfo appInfo = context.getApplicationInfo();
    175         PackageManager pm = context.getPackageManager();
    176         mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode,
    177                 ActionBar.NAVIGATION_MODE_STANDARD);
    178         mTitle = a.getText(R.styleable.ActionBar_title);
    179         mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
    180 
    181         mLogo = a.getDrawable(R.styleable.ActionBar_logo);
    182         if (mLogo == null) {
    183             if (context instanceof Activity) {
    184                 try {
    185                     mLogo = pm.getActivityLogo(((Activity) context).getComponentName());
    186                 } catch (NameNotFoundException e) {
    187                     Log.e(TAG, "Activity component name not found!", e);
    188                 }
    189             }
    190             if (mLogo == null) {
    191                 mLogo = appInfo.loadLogo(pm);
    192             }
    193         }
    194 
    195         mIcon = a.getDrawable(R.styleable.ActionBar_icon);
    196         if (mIcon == null) {
    197             if (context instanceof Activity) {
    198                 try {
    199                     mIcon = pm.getActivityIcon(((Activity) context).getComponentName());
    200                 } catch (NameNotFoundException e) {
    201                     Log.e(TAG, "Activity component name not found!", e);
    202                 }
    203             }
    204             if (mIcon == null) {
    205                 mIcon = appInfo.loadIcon(pm);
    206             }
    207         }
    208 
    209         final LayoutInflater inflater = LayoutInflater.from(context);
    210 
    211         final int homeResId = a.getResourceId(
    212                 com.android.internal.R.styleable.ActionBar_homeLayout,
    213                 com.android.internal.R.layout.action_bar_home);
    214 
    215         mHomeLayout = (HomeView) inflater.inflate(homeResId, this, false);
    216 
    217         mExpandedHomeLayout = (HomeView) inflater.inflate(homeResId, this, false);
    218         mExpandedHomeLayout.setUp(true);
    219         mExpandedHomeLayout.setOnClickListener(mExpandedActionViewUpListener);
    220         mExpandedHomeLayout.setContentDescription(getResources().getText(
    221                 R.string.action_bar_up_description));
    222 
    223         mTitleStyleRes = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0);
    224         mSubtitleStyleRes = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0);
    225         mProgressStyle = a.getResourceId(R.styleable.ActionBar_progressBarStyle, 0);
    226         mIndeterminateProgressStyle = a.getResourceId(
    227                 R.styleable.ActionBar_indeterminateProgressStyle, 0);
    228 
    229         mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.ActionBar_progressBarPadding, 0);
    230         mItemPadding = a.getDimensionPixelOffset(R.styleable.ActionBar_itemPadding, 0);
    231 
    232         setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT));
    233 
    234         final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
    235         if (customNavId != 0) {
    236             mCustomNavView = (View) inflater.inflate(customNavId, this, false);
    237             mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
    238             setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM);
    239         }
    240 
    241         mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
    242 
    243         a.recycle();
    244 
    245         mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
    246         mHomeLayout.setOnClickListener(mUpClickListener);
    247         mHomeLayout.setClickable(true);
    248         mHomeLayout.setFocusable(true);
    249     }
    250 
    251     @Override
    252     protected void onConfigurationChanged(Configuration newConfig) {
    253         super.onConfigurationChanged(newConfig);
    254 
    255         mTitleView = null;
    256         mSubtitleView = null;
    257         mTitleUpView = null;
    258         if (mTitleLayout != null && mTitleLayout.getParent() == this) {
    259             removeView(mTitleLayout);
    260         }
    261         mTitleLayout = null;
    262         if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
    263             initTitle();
    264         }
    265 
    266         if (mTabScrollView != null && mIncludeTabs) {
    267             ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
    268             if (lp != null) {
    269                 lp.width = LayoutParams.WRAP_CONTENT;
    270                 lp.height = LayoutParams.MATCH_PARENT;
    271             }
    272             mTabScrollView.setAllowCollapse(true);
    273         }
    274     }
    275 
    276     /**
    277      * Set the window callback used to invoke menu items; used for dispatching home button presses.
    278      * @param cb Window callback to dispatch to
    279      */
    280     public void setWindowCallback(Window.Callback cb) {
    281         mWindowCallback = cb;
    282     }
    283 
    284     @Override
    285     public void onDetachedFromWindow() {
    286         super.onDetachedFromWindow();
    287         removeCallbacks(mTabSelector);
    288         if (mActionMenuPresenter != null) {
    289             mActionMenuPresenter.hideOverflowMenu();
    290             mActionMenuPresenter.hideSubMenus();
    291         }
    292     }
    293 
    294     @Override
    295     public boolean shouldDelayChildPressedState() {
    296         return false;
    297     }
    298 
    299     public void initProgress() {
    300         mProgressView = new ProgressBar(mContext, null, 0, mProgressStyle);
    301         mProgressView.setId(R.id.progress_horizontal);
    302         mProgressView.setMax(10000);
    303         addView(mProgressView);
    304     }
    305 
    306     public void initIndeterminateProgress() {
    307         mIndeterminateProgressView = new ProgressBar(mContext, null, 0,
    308                 mIndeterminateProgressStyle);
    309         mIndeterminateProgressView.setId(R.id.progress_circular);
    310         addView(mIndeterminateProgressView);
    311     }
    312 
    313     @Override
    314     public void setSplitActionBar(boolean splitActionBar) {
    315         if (mSplitActionBar != splitActionBar) {
    316             if (mMenuView != null) {
    317                 final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
    318                 if (oldParent != null) {
    319                     oldParent.removeView(mMenuView);
    320                 }
    321                 if (splitActionBar) {
    322                     if (mSplitView != null) {
    323                         mSplitView.addView(mMenuView);
    324                     }
    325                 } else {
    326                     addView(mMenuView);
    327                 }
    328             }
    329             if (mSplitView != null) {
    330                 mSplitView.setVisibility(splitActionBar ? VISIBLE : GONE);
    331             }
    332             super.setSplitActionBar(splitActionBar);
    333         }
    334     }
    335 
    336     public boolean isSplitActionBar() {
    337         return mSplitActionBar;
    338     }
    339 
    340     public boolean hasEmbeddedTabs() {
    341         return mIncludeTabs;
    342     }
    343 
    344     public void setEmbeddedTabView(ScrollingTabContainerView tabs) {
    345         if (mTabScrollView != null) {
    346             removeView(mTabScrollView);
    347         }
    348         mTabScrollView = tabs;
    349         mIncludeTabs = tabs != null;
    350         if (mIncludeTabs && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) {
    351             addView(mTabScrollView);
    352             ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
    353             lp.width = LayoutParams.WRAP_CONTENT;
    354             lp.height = LayoutParams.MATCH_PARENT;
    355             tabs.setAllowCollapse(true);
    356         }
    357     }
    358 
    359     public void setCallback(OnNavigationListener callback) {
    360         mCallback = callback;
    361     }
    362 
    363     public void setMenu(Menu menu, MenuPresenter.Callback cb) {
    364         if (menu == mOptionsMenu) return;
    365 
    366         if (mOptionsMenu != null) {
    367             mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);
    368             mOptionsMenu.removeMenuPresenter(mExpandedMenuPresenter);
    369         }
    370 
    371         MenuBuilder builder = (MenuBuilder) menu;
    372         mOptionsMenu = builder;
    373         if (mMenuView != null) {
    374             final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
    375             if (oldParent != null) {
    376                 oldParent.removeView(mMenuView);
    377             }
    378         }
    379         if (mActionMenuPresenter == null) {
    380             mActionMenuPresenter = new ActionMenuPresenter(mContext);
    381             mActionMenuPresenter.setCallback(cb);
    382             mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);
    383             mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
    384         }
    385 
    386         ActionMenuView menuView;
    387         final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
    388                 LayoutParams.MATCH_PARENT);
    389         if (!mSplitActionBar) {
    390             mActionMenuPresenter.setExpandedActionViewsExclusive(
    391                     getResources().getBoolean(
    392                     com.android.internal.R.bool.action_bar_expanded_action_views_exclusive));
    393             configPresenters(builder);
    394             menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
    395             final ViewGroup oldParent = (ViewGroup) menuView.getParent();
    396             if (oldParent != null && oldParent != this) {
    397                 oldParent.removeView(menuView);
    398             }
    399             addView(menuView, layoutParams);
    400         } else {
    401             mActionMenuPresenter.setExpandedActionViewsExclusive(false);
    402             // Allow full screen width in split mode.
    403             mActionMenuPresenter.setWidthLimit(
    404                     getContext().getResources().getDisplayMetrics().widthPixels, true);
    405             // No limit to the item count; use whatever will fit.
    406             mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
    407             // Span the whole width
    408             layoutParams.width = LayoutParams.MATCH_PARENT;
    409             configPresenters(builder);
    410             menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
    411             if (mSplitView != null) {
    412                 final ViewGroup oldParent = (ViewGroup) menuView.getParent();
    413                 if (oldParent != null && oldParent != mSplitView) {
    414                     oldParent.removeView(menuView);
    415                 }
    416                 menuView.setVisibility(getAnimatedVisibility());
    417                 mSplitView.addView(menuView, layoutParams);
    418             } else {
    419                 // We'll add this later if we missed it this time.
    420                 menuView.setLayoutParams(layoutParams);
    421             }
    422         }
    423         mMenuView = menuView;
    424     }
    425 
    426     private void configPresenters(MenuBuilder builder) {
    427         if (builder != null) {
    428             builder.addMenuPresenter(mActionMenuPresenter);
    429             builder.addMenuPresenter(mExpandedMenuPresenter);
    430         } else {
    431             mActionMenuPresenter.initForMenu(mContext, null);
    432             mExpandedMenuPresenter.initForMenu(mContext, null);
    433             mActionMenuPresenter.updateMenuView(true);
    434             mExpandedMenuPresenter.updateMenuView(true);
    435         }
    436     }
    437 
    438     public boolean hasExpandedActionView() {
    439         return mExpandedMenuPresenter != null &&
    440                 mExpandedMenuPresenter.mCurrentExpandedItem != null;
    441     }
    442 
    443     public void collapseActionView() {
    444         final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
    445                 mExpandedMenuPresenter.mCurrentExpandedItem;
    446         if (item != null) {
    447             item.collapseActionView();
    448         }
    449     }
    450 
    451     public void setCustomNavigationView(View view) {
    452         final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
    453         if (mCustomNavView != null && showCustom) {
    454             removeView(mCustomNavView);
    455         }
    456         mCustomNavView = view;
    457         if (mCustomNavView != null && showCustom) {
    458             addView(mCustomNavView);
    459         }
    460     }
    461 
    462     public CharSequence getTitle() {
    463         return mTitle;
    464     }
    465 
    466     /**
    467      * Set the action bar title. This will always replace or override window titles.
    468      * @param title Title to set
    469      *
    470      * @see #setWindowTitle(CharSequence)
    471      */
    472     public void setTitle(CharSequence title) {
    473         mUserTitle = true;
    474         setTitleImpl(title);
    475     }
    476 
    477     /**
    478      * Set the window title. A window title will always be replaced or overridden by a user title.
    479      * @param title Title to set
    480      *
    481      * @see #setTitle(CharSequence)
    482      */
    483     public void setWindowTitle(CharSequence title) {
    484         if (!mUserTitle) {
    485             setTitleImpl(title);
    486         }
    487     }
    488 
    489     private void setTitleImpl(CharSequence title) {
    490         mTitle = title;
    491         if (mTitleView != null) {
    492             mTitleView.setText(title);
    493             final boolean visible = mExpandedActionView == null &&
    494                     (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 &&
    495                     (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle));
    496             mTitleLayout.setVisibility(visible ? VISIBLE : GONE);
    497         }
    498         if (mLogoNavItem != null) {
    499             mLogoNavItem.setTitle(title);
    500         }
    501     }
    502 
    503     public CharSequence getSubtitle() {
    504         return mSubtitle;
    505     }
    506 
    507     public void setSubtitle(CharSequence subtitle) {
    508         mSubtitle = subtitle;
    509         if (mSubtitleView != null) {
    510             mSubtitleView.setText(subtitle);
    511             mSubtitleView.setVisibility(subtitle != null ? VISIBLE : GONE);
    512             final boolean visible = mExpandedActionView == null &&
    513                     (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 &&
    514                     (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle));
    515             mTitleLayout.setVisibility(visible ? VISIBLE : GONE);
    516         }
    517     }
    518 
    519     public void setHomeButtonEnabled(boolean enable) {
    520         mHomeLayout.setEnabled(enable);
    521         mHomeLayout.setFocusable(enable);
    522         // Make sure the home button has an accurate content description for accessibility.
    523         if (!enable) {
    524             mHomeLayout.setContentDescription(null);
    525         } else if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
    526             mHomeLayout.setContentDescription(mContext.getResources().getText(
    527                     R.string.action_bar_up_description));
    528         } else {
    529             mHomeLayout.setContentDescription(mContext.getResources().getText(
    530                     R.string.action_bar_home_description));
    531         }
    532     }
    533 
    534     public void setDisplayOptions(int options) {
    535         final int flagsChanged = mDisplayOptions == -1 ? -1 : options ^ mDisplayOptions;
    536         mDisplayOptions = options;
    537 
    538         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
    539             final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
    540             final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE;
    541             mHomeLayout.setVisibility(vis);
    542 
    543             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
    544                 final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
    545                 mHomeLayout.setUp(setUp);
    546 
    547                 // Showing home as up implicitly enables interaction with it.
    548                 // In honeycomb it was always enabled, so make this transition
    549                 // a bit easier for developers in the common case.
    550                 // (It would be silly to show it as up without responding to it.)
    551                 if (setUp) {
    552                     setHomeButtonEnabled(true);
    553                 }
    554             }
    555 
    556             if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
    557                 final boolean logoVis = mLogo != null && (options & ActionBar.DISPLAY_USE_LOGO) != 0;
    558                 mHomeLayout.setIcon(logoVis ? mLogo : mIcon);
    559             }
    560 
    561             if ((flagsChanged & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
    562                 if ((options & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
    563                     initTitle();
    564                 } else {
    565                     removeView(mTitleLayout);
    566                 }
    567             }
    568 
    569             if (mTitleLayout != null && (flagsChanged &
    570                     (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) {
    571                 final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
    572                 mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
    573                 mTitleLayout.setEnabled(!showHome && homeAsUp);
    574             }
    575 
    576             if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
    577                 if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
    578                     addView(mCustomNavView);
    579                 } else {
    580                     removeView(mCustomNavView);
    581                 }
    582             }
    583 
    584             requestLayout();
    585         } else {
    586             invalidate();
    587         }
    588 
    589         // Make sure the home button has an accurate content description for accessibility.
    590         if (!mHomeLayout.isEnabled()) {
    591             mHomeLayout.setContentDescription(null);
    592         } else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
    593             mHomeLayout.setContentDescription(mContext.getResources().getText(
    594                     R.string.action_bar_up_description));
    595         } else {
    596             mHomeLayout.setContentDescription(mContext.getResources().getText(
    597                     R.string.action_bar_home_description));
    598         }
    599     }
    600 
    601     public void setIcon(Drawable icon) {
    602         mIcon = icon;
    603         if (icon != null &&
    604                 ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) {
    605             mHomeLayout.setIcon(icon);
    606         }
    607     }
    608 
    609     public void setIcon(int resId) {
    610         setIcon(mContext.getResources().getDrawable(resId));
    611     }
    612 
    613     public void setLogo(Drawable logo) {
    614         mLogo = logo;
    615         if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
    616             mHomeLayout.setIcon(logo);
    617         }
    618     }
    619 
    620     public void setLogo(int resId) {
    621         setLogo(mContext.getResources().getDrawable(resId));
    622     }
    623 
    624     public void setNavigationMode(int mode) {
    625         final int oldMode = mNavigationMode;
    626         if (mode != oldMode) {
    627             switch (oldMode) {
    628             case ActionBar.NAVIGATION_MODE_LIST:
    629                 if (mListNavLayout != null) {
    630                     removeView(mListNavLayout);
    631                 }
    632                 break;
    633             case ActionBar.NAVIGATION_MODE_TABS:
    634                 if (mTabScrollView != null && mIncludeTabs) {
    635                     removeView(mTabScrollView);
    636                 }
    637             }
    638 
    639             switch (mode) {
    640             case ActionBar.NAVIGATION_MODE_LIST:
    641                 if (mSpinner == null) {
    642                     mSpinner = new Spinner(mContext, null,
    643                             com.android.internal.R.attr.actionDropDownStyle);
    644                     mListNavLayout = new LinearLayout(mContext, null,
    645                             com.android.internal.R.attr.actionBarTabBarStyle);
    646                     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
    647                             LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
    648                     params.gravity = Gravity.CENTER;
    649                     mListNavLayout.addView(mSpinner, params);
    650                 }
    651                 if (mSpinner.getAdapter() != mSpinnerAdapter) {
    652                     mSpinner.setAdapter(mSpinnerAdapter);
    653                 }
    654                 mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
    655                 addView(mListNavLayout);
    656                 break;
    657             case ActionBar.NAVIGATION_MODE_TABS:
    658                 if (mTabScrollView != null && mIncludeTabs) {
    659                     addView(mTabScrollView);
    660                 }
    661                 break;
    662             }
    663             mNavigationMode = mode;
    664             requestLayout();
    665         }
    666     }
    667 
    668     public void setDropdownAdapter(SpinnerAdapter adapter) {
    669         mSpinnerAdapter = adapter;
    670         if (mSpinner != null) {
    671             mSpinner.setAdapter(adapter);
    672         }
    673     }
    674 
    675     public SpinnerAdapter getDropdownAdapter() {
    676         return mSpinnerAdapter;
    677     }
    678 
    679     public void setDropdownSelectedPosition(int position) {
    680         mSpinner.setSelection(position);
    681     }
    682 
    683     public int getDropdownSelectedPosition() {
    684         return mSpinner.getSelectedItemPosition();
    685     }
    686 
    687     public View getCustomNavigationView() {
    688         return mCustomNavView;
    689     }
    690 
    691     public int getNavigationMode() {
    692         return mNavigationMode;
    693     }
    694 
    695     public int getDisplayOptions() {
    696         return mDisplayOptions;
    697     }
    698 
    699     @Override
    700     protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
    701         // Used by custom nav views if they don't supply layout params. Everything else
    702         // added to an ActionBarView should have them already.
    703         return new ActionBar.LayoutParams(DEFAULT_CUSTOM_GRAVITY);
    704     }
    705 
    706     @Override
    707     protected void onFinishInflate() {
    708         super.onFinishInflate();
    709 
    710         addView(mHomeLayout);
    711 
    712         if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
    713             final ViewParent parent = mCustomNavView.getParent();
    714             if (parent != this) {
    715                 if (parent instanceof ViewGroup) {
    716                     ((ViewGroup) parent).removeView(mCustomNavView);
    717                 }
    718                 addView(mCustomNavView);
    719             }
    720         }
    721     }
    722 
    723     private void initTitle() {
    724         if (mTitleLayout == null) {
    725             LayoutInflater inflater = LayoutInflater.from(getContext());
    726             mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item,
    727                     this, false);
    728             mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
    729             mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
    730             mTitleUpView = (View) mTitleLayout.findViewById(R.id.up);
    731 
    732             mTitleLayout.setOnClickListener(mUpClickListener);
    733 
    734             if (mTitleStyleRes != 0) {
    735                 mTitleView.setTextAppearance(mContext, mTitleStyleRes);
    736             }
    737             if (mTitle != null) {
    738                 mTitleView.setText(mTitle);
    739             }
    740 
    741             if (mSubtitleStyleRes != 0) {
    742                 mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
    743             }
    744             if (mSubtitle != null) {
    745                 mSubtitleView.setText(mSubtitle);
    746                 mSubtitleView.setVisibility(VISIBLE);
    747             }
    748 
    749             final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
    750             final boolean showHome = (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0;
    751             mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
    752             mTitleLayout.setEnabled(homeAsUp && !showHome);
    753         }
    754 
    755         addView(mTitleLayout);
    756         if (mExpandedActionView != null ||
    757                 (TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) {
    758             // Don't show while in expanded mode or with empty text
    759             mTitleLayout.setVisibility(GONE);
    760         }
    761     }
    762 
    763     public void setContextView(ActionBarContextView view) {
    764         mContextView = view;
    765     }
    766 
    767     public void setCollapsable(boolean collapsable) {
    768         mIsCollapsable = collapsable;
    769     }
    770 
    771     public boolean isCollapsed() {
    772         return mIsCollapsed;
    773     }
    774 
    775     @Override
    776     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    777         final int childCount = getChildCount();
    778         if (mIsCollapsable) {
    779             int visibleChildren = 0;
    780             for (int i = 0; i < childCount; i++) {
    781                 final View child = getChildAt(i);
    782                 if (child.getVisibility() != GONE &&
    783                         !(child == mMenuView && mMenuView.getChildCount() == 0)) {
    784                     visibleChildren++;
    785                 }
    786             }
    787 
    788             if (visibleChildren == 0) {
    789                 // No size for an empty action bar when collapsable.
    790                 setMeasuredDimension(0, 0);
    791                 mIsCollapsed = true;
    792                 return;
    793             }
    794         }
    795         mIsCollapsed = false;
    796 
    797         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    798         if (widthMode != MeasureSpec.EXACTLY) {
    799             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
    800                     "with android:layout_width=\"match_parent\" (or fill_parent)");
    801         }
    802 
    803         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    804         if (heightMode != MeasureSpec.AT_MOST) {
    805             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
    806                     "with android:layout_height=\"wrap_content\"");
    807         }
    808 
    809         int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
    810 
    811         int maxHeight = mContentHeight > 0 ?
    812                 mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
    813 
    814         final int verticalPadding = getPaddingTop() + getPaddingBottom();
    815         final int paddingLeft = getPaddingLeft();
    816         final int paddingRight = getPaddingRight();
    817         final int height = maxHeight - verticalPadding;
    818         final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
    819 
    820         int availableWidth = contentWidth - paddingLeft - paddingRight;
    821         int leftOfCenter = availableWidth / 2;
    822         int rightOfCenter = leftOfCenter;
    823 
    824         HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
    825 
    826         if (homeLayout.getVisibility() != GONE) {
    827             final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams();
    828             int homeWidthSpec;
    829             if (lp.width < 0) {
    830                 homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
    831             } else {
    832                 homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
    833             }
    834             homeLayout.measure(homeWidthSpec,
    835                     MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
    836             final int homeWidth = homeLayout.getMeasuredWidth() + homeLayout.getLeftOffset();
    837             availableWidth = Math.max(0, availableWidth - homeWidth);
    838             leftOfCenter = Math.max(0, availableWidth - homeWidth);
    839         }
    840 
    841         if (mMenuView != null && mMenuView.getParent() == this) {
    842             availableWidth = measureChildView(mMenuView, availableWidth,
    843                     childSpecHeight, 0);
    844             rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth());
    845         }
    846 
    847         if (mIndeterminateProgressView != null &&
    848                 mIndeterminateProgressView.getVisibility() != GONE) {
    849             availableWidth = measureChildView(mIndeterminateProgressView, availableWidth,
    850                     childSpecHeight, 0);
    851             rightOfCenter = Math.max(0,
    852                     rightOfCenter - mIndeterminateProgressView.getMeasuredWidth());
    853         }
    854 
    855         final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
    856                 (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
    857 
    858         if (mExpandedActionView == null) {
    859             switch (mNavigationMode) {
    860                 case ActionBar.NAVIGATION_MODE_LIST:
    861                     if (mListNavLayout != null) {
    862                         final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding;
    863                         availableWidth = Math.max(0, availableWidth - itemPaddingSize);
    864                         leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize);
    865                         mListNavLayout.measure(
    866                                 MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
    867                                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
    868                         final int listNavWidth = mListNavLayout.getMeasuredWidth();
    869                         availableWidth = Math.max(0, availableWidth - listNavWidth);
    870                         leftOfCenter = Math.max(0, leftOfCenter - listNavWidth);
    871                     }
    872                     break;
    873                 case ActionBar.NAVIGATION_MODE_TABS:
    874                     if (mTabScrollView != null) {
    875                         final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding;
    876                         availableWidth = Math.max(0, availableWidth - itemPaddingSize);
    877                         leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize);
    878                         mTabScrollView.measure(
    879                                 MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
    880                                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
    881                         final int tabWidth = mTabScrollView.getMeasuredWidth();
    882                         availableWidth = Math.max(0, availableWidth - tabWidth);
    883                         leftOfCenter = Math.max(0, leftOfCenter - tabWidth);
    884                     }
    885                     break;
    886             }
    887         }
    888 
    889         View customView = null;
    890         if (mExpandedActionView != null) {
    891             customView = mExpandedActionView;
    892         } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 &&
    893                 mCustomNavView != null) {
    894             customView = mCustomNavView;
    895         }
    896 
    897         if (customView != null) {
    898             final ViewGroup.LayoutParams lp = generateLayoutParams(customView.getLayoutParams());
    899             final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
    900                     (ActionBar.LayoutParams) lp : null;
    901 
    902             int horizontalMargin = 0;
    903             int verticalMargin = 0;
    904             if (ablp != null) {
    905                 horizontalMargin = ablp.leftMargin + ablp.rightMargin;
    906                 verticalMargin = ablp.topMargin + ablp.bottomMargin;
    907             }
    908 
    909             // If the action bar is wrapping to its content height, don't allow a custom
    910             // view to MATCH_PARENT.
    911             int customNavHeightMode;
    912             if (mContentHeight <= 0) {
    913                 customNavHeightMode = MeasureSpec.AT_MOST;
    914             } else {
    915                 customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
    916                         MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
    917             }
    918             final int customNavHeight = Math.max(0,
    919                     (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin);
    920 
    921             final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
    922                     MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
    923             int customNavWidth = Math.max(0,
    924                     (lp.width >= 0 ? Math.min(lp.width, availableWidth) : availableWidth)
    925                     - horizontalMargin);
    926             final int hgrav = (ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY) &
    927                     Gravity.HORIZONTAL_GRAVITY_MASK;
    928 
    929             // Centering a custom view is treated specially; we try to center within the whole
    930             // action bar rather than in the available space.
    931             if (hgrav == Gravity.CENTER_HORIZONTAL && lp.width == LayoutParams.MATCH_PARENT) {
    932                 customNavWidth = Math.min(leftOfCenter, rightOfCenter) * 2;
    933             }
    934 
    935             customView.measure(
    936                     MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
    937                     MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
    938             availableWidth -= horizontalMargin + customView.getMeasuredWidth();
    939         }
    940 
    941         if (mExpandedActionView == null && showTitle) {
    942             availableWidth = measureChildView(mTitleLayout, availableWidth,
    943                     MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY), 0);
    944             leftOfCenter = Math.max(0, leftOfCenter - mTitleLayout.getMeasuredWidth());
    945         }
    946 
    947         if (mContentHeight <= 0) {
    948             int measuredHeight = 0;
    949             for (int i = 0; i < childCount; i++) {
    950                 View v = getChildAt(i);
    951                 int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
    952                 if (paddedViewHeight > measuredHeight) {
    953                     measuredHeight = paddedViewHeight;
    954                 }
    955             }
    956             setMeasuredDimension(contentWidth, measuredHeight);
    957         } else {
    958             setMeasuredDimension(contentWidth, maxHeight);
    959         }
    960 
    961         if (mContextView != null) {
    962             mContextView.setContentHeight(getMeasuredHeight());
    963         }
    964 
    965         if (mProgressView != null && mProgressView.getVisibility() != GONE) {
    966             mProgressView.measure(MeasureSpec.makeMeasureSpec(
    967                     contentWidth - mProgressBarPadding * 2, MeasureSpec.EXACTLY),
    968                     MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST));
    969         }
    970     }
    971 
    972     @Override
    973     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    974         int x = getPaddingLeft();
    975         final int y = getPaddingTop();
    976         final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
    977 
    978         if (contentHeight <= 0) {
    979             // Nothing to do if we can't see anything.
    980             return;
    981         }
    982 
    983         HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
    984         if (homeLayout.getVisibility() != GONE) {
    985             final int leftOffset = homeLayout.getLeftOffset();
    986             x += positionChild(homeLayout, x + leftOffset, y, contentHeight) + leftOffset;
    987         }
    988 
    989         if (mExpandedActionView == null) {
    990             final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
    991                     (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
    992             if (showTitle) {
    993                 x += positionChild(mTitleLayout, x, y, contentHeight);
    994             }
    995 
    996             switch (mNavigationMode) {
    997                 case ActionBar.NAVIGATION_MODE_STANDARD:
    998                     break;
    999                 case ActionBar.NAVIGATION_MODE_LIST:
   1000                     if (mListNavLayout != null) {
   1001                         if (showTitle) x += mItemPadding;
   1002                         x += positionChild(mListNavLayout, x, y, contentHeight) + mItemPadding;
   1003                     }
   1004                     break;
   1005                 case ActionBar.NAVIGATION_MODE_TABS:
   1006                     if (mTabScrollView != null) {
   1007                         if (showTitle) x += mItemPadding;
   1008                         x += positionChild(mTabScrollView, x, y, contentHeight) + mItemPadding;
   1009                     }
   1010                     break;
   1011             }
   1012         }
   1013 
   1014         int menuLeft = r - l - getPaddingRight();
   1015         if (mMenuView != null && mMenuView.getParent() == this) {
   1016             positionChildInverse(mMenuView, menuLeft, y, contentHeight);
   1017             menuLeft -= mMenuView.getMeasuredWidth();
   1018         }
   1019 
   1020         if (mIndeterminateProgressView != null &&
   1021                 mIndeterminateProgressView.getVisibility() != GONE) {
   1022             positionChildInverse(mIndeterminateProgressView, menuLeft, y, contentHeight);
   1023             menuLeft -= mIndeterminateProgressView.getMeasuredWidth();
   1024         }
   1025 
   1026         View customView = null;
   1027         if (mExpandedActionView != null) {
   1028             customView = mExpandedActionView;
   1029         } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 &&
   1030                 mCustomNavView != null) {
   1031             customView = mCustomNavView;
   1032         }
   1033         if (customView != null) {
   1034             ViewGroup.LayoutParams lp = customView.getLayoutParams();
   1035             final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
   1036                     (ActionBar.LayoutParams) lp : null;
   1037 
   1038             final int gravity = ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY;
   1039             final int navWidth = customView.getMeasuredWidth();
   1040 
   1041             int topMargin = 0;
   1042             int bottomMargin = 0;
   1043             if (ablp != null) {
   1044                 x += ablp.leftMargin;
   1045                 menuLeft -= ablp.rightMargin;
   1046                 topMargin = ablp.topMargin;
   1047                 bottomMargin = ablp.bottomMargin;
   1048             }
   1049 
   1050             int hgravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
   1051             // See if we actually have room to truly center; if not push against left or right.
   1052             if (hgravity == Gravity.CENTER_HORIZONTAL) {
   1053                 final int centeredLeft = ((mRight - mLeft) - navWidth) / 2;
   1054                 if (centeredLeft < x) {
   1055                     hgravity = Gravity.LEFT;
   1056                 } else if (centeredLeft + navWidth > menuLeft) {
   1057                     hgravity = Gravity.RIGHT;
   1058                 }
   1059             } else if (gravity == -1) {
   1060                 hgravity = Gravity.LEFT;
   1061             }
   1062 
   1063             int xpos = 0;
   1064             switch (hgravity) {
   1065                 case Gravity.CENTER_HORIZONTAL:
   1066                     xpos = ((mRight - mLeft) - navWidth) / 2;
   1067                     break;
   1068                 case Gravity.LEFT:
   1069                     xpos = x;
   1070                     break;
   1071                 case Gravity.RIGHT:
   1072                     xpos = menuLeft - navWidth;
   1073                     break;
   1074             }
   1075 
   1076             int vgravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
   1077 
   1078             if (gravity == -1) {
   1079                 vgravity = Gravity.CENTER_VERTICAL;
   1080             }
   1081 
   1082             int ypos = 0;
   1083             switch (vgravity) {
   1084                 case Gravity.CENTER_VERTICAL:
   1085                     final int paddedTop = getPaddingTop();
   1086                     final int paddedBottom = mBottom - mTop - getPaddingBottom();
   1087                     ypos = ((paddedBottom - paddedTop) - customView.getMeasuredHeight()) / 2;
   1088                     break;
   1089                 case Gravity.TOP:
   1090                     ypos = getPaddingTop() + topMargin;
   1091                     break;
   1092                 case Gravity.BOTTOM:
   1093                     ypos = getHeight() - getPaddingBottom() - customView.getMeasuredHeight()
   1094                             - bottomMargin;
   1095                     break;
   1096             }
   1097             final int customWidth = customView.getMeasuredWidth();
   1098             customView.layout(xpos, ypos, xpos + customWidth,
   1099                     ypos + customView.getMeasuredHeight());
   1100             x += customWidth;
   1101         }
   1102 
   1103         if (mProgressView != null) {
   1104             mProgressView.bringToFront();
   1105             final int halfProgressHeight = mProgressView.getMeasuredHeight() / 2;
   1106             mProgressView.layout(mProgressBarPadding, -halfProgressHeight,
   1107                     mProgressBarPadding + mProgressView.getMeasuredWidth(), halfProgressHeight);
   1108         }
   1109     }
   1110 
   1111     @Override
   1112     public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
   1113         return new ActionBar.LayoutParams(getContext(), attrs);
   1114     }
   1115 
   1116     @Override
   1117     public ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
   1118         if (lp == null) {
   1119             lp = generateDefaultLayoutParams();
   1120         }
   1121         return lp;
   1122     }
   1123 
   1124     @Override
   1125     public Parcelable onSaveInstanceState() {
   1126         Parcelable superState = super.onSaveInstanceState();
   1127         SavedState state = new SavedState(superState);
   1128 
   1129         if (mExpandedMenuPresenter != null && mExpandedMenuPresenter.mCurrentExpandedItem != null) {
   1130             state.expandedMenuItemId = mExpandedMenuPresenter.mCurrentExpandedItem.getItemId();
   1131         }
   1132 
   1133         state.isOverflowOpen = isOverflowMenuShowing();
   1134 
   1135         return state;
   1136     }
   1137 
   1138     @Override
   1139     public void onRestoreInstanceState(Parcelable p) {
   1140         SavedState state = (SavedState) p;
   1141 
   1142         super.onRestoreInstanceState(state.getSuperState());
   1143 
   1144         if (state.expandedMenuItemId != 0 &&
   1145                 mExpandedMenuPresenter != null && mOptionsMenu != null) {
   1146             final MenuItem item = mOptionsMenu.findItem(state.expandedMenuItemId);
   1147             if (item != null) {
   1148                 item.expandActionView();
   1149             }
   1150         }
   1151 
   1152         if (state.isOverflowOpen) {
   1153             postShowOverflowMenu();
   1154         }
   1155     }
   1156 
   1157     static class SavedState extends BaseSavedState {
   1158         int expandedMenuItemId;
   1159         boolean isOverflowOpen;
   1160 
   1161         SavedState(Parcelable superState) {
   1162             super(superState);
   1163         }
   1164 
   1165         private SavedState(Parcel in) {
   1166             super(in);
   1167             expandedMenuItemId = in.readInt();
   1168             isOverflowOpen = in.readInt() != 0;
   1169         }
   1170 
   1171         @Override
   1172         public void writeToParcel(Parcel out, int flags) {
   1173             super.writeToParcel(out, flags);
   1174             out.writeInt(expandedMenuItemId);
   1175             out.writeInt(isOverflowOpen ? 1 : 0);
   1176         }
   1177 
   1178         public static final Parcelable.Creator<SavedState> CREATOR =
   1179                 new Parcelable.Creator<SavedState>() {
   1180             public SavedState createFromParcel(Parcel in) {
   1181                 return new SavedState(in);
   1182             }
   1183 
   1184             public SavedState[] newArray(int size) {
   1185                 return new SavedState[size];
   1186             }
   1187         };
   1188     }
   1189 
   1190     private static class HomeView extends FrameLayout {
   1191         private View mUpView;
   1192         private ImageView mIconView;
   1193         private int mUpWidth;
   1194 
   1195         public HomeView(Context context) {
   1196             this(context, null);
   1197         }
   1198 
   1199         public HomeView(Context context, AttributeSet attrs) {
   1200             super(context, attrs);
   1201         }
   1202 
   1203         public void setUp(boolean isUp) {
   1204             mUpView.setVisibility(isUp ? VISIBLE : GONE);
   1205         }
   1206 
   1207         public void setIcon(Drawable icon) {
   1208             mIconView.setImageDrawable(icon);
   1209         }
   1210 
   1211         @Override
   1212         public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
   1213             onPopulateAccessibilityEvent(event);
   1214             return true;
   1215         }
   1216 
   1217         @Override
   1218         public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
   1219             super.onPopulateAccessibilityEvent(event);
   1220             final CharSequence cdesc = getContentDescription();
   1221             if (!TextUtils.isEmpty(cdesc)) {
   1222                 event.getText().add(cdesc);
   1223             }
   1224         }
   1225 
   1226         @Override
   1227         public boolean dispatchHoverEvent(MotionEvent event) {
   1228             // Don't allow children to hover; we want this to be treated as a single component.
   1229             return onHoverEvent(event);
   1230         }
   1231 
   1232         @Override
   1233         protected void onFinishInflate() {
   1234             mUpView = findViewById(com.android.internal.R.id.up);
   1235             mIconView = (ImageView) findViewById(com.android.internal.R.id.home);
   1236         }
   1237 
   1238         public int getLeftOffset() {
   1239             return mUpView.getVisibility() == GONE ? mUpWidth : 0;
   1240         }
   1241 
   1242         @Override
   1243         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   1244             measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
   1245             final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
   1246             mUpWidth = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
   1247             int width = mUpView.getVisibility() == GONE ? 0 : mUpWidth;
   1248             int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
   1249             measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
   1250             final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
   1251             width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
   1252             height = Math.max(height,
   1253                     iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
   1254 
   1255             final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
   1256             final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
   1257             final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
   1258             final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
   1259 
   1260             switch (widthMode) {
   1261                 case MeasureSpec.AT_MOST:
   1262                     width = Math.min(width, widthSize);
   1263                     break;
   1264                 case MeasureSpec.EXACTLY:
   1265                     width = widthSize;
   1266                     break;
   1267                 case MeasureSpec.UNSPECIFIED:
   1268                 default:
   1269                     break;
   1270             }
   1271             switch (heightMode) {
   1272                 case MeasureSpec.AT_MOST:
   1273                     height = Math.min(height, heightSize);
   1274                     break;
   1275                 case MeasureSpec.EXACTLY:
   1276                     height = heightSize;
   1277                     break;
   1278                 case MeasureSpec.UNSPECIFIED:
   1279                 default:
   1280                     break;
   1281             }
   1282             setMeasuredDimension(width, height);
   1283         }
   1284 
   1285         @Override
   1286         protected void onLayout(boolean changed, int l, int t, int r, int b) {
   1287             final int vCenter = (b - t) / 2;
   1288             int width = r - l;
   1289             int upOffset = 0;
   1290             if (mUpView.getVisibility() != GONE) {
   1291                 final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
   1292                 final int upHeight = mUpView.getMeasuredHeight();
   1293                 final int upWidth = mUpView.getMeasuredWidth();
   1294                 final int upTop = vCenter - upHeight / 2;
   1295                 mUpView.layout(0, upTop, upWidth, upTop + upHeight);
   1296                 upOffset = upLp.leftMargin + upWidth + upLp.rightMargin;
   1297                 width -= upOffset;
   1298                 l += upOffset;
   1299             }
   1300             final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
   1301             final int iconHeight = mIconView.getMeasuredHeight();
   1302             final int iconWidth = mIconView.getMeasuredWidth();
   1303             final int hCenter = (r - l) / 2;
   1304             final int iconLeft = upOffset + Math.max(iconLp.leftMargin, hCenter - iconWidth / 2);
   1305             final int iconTop = Math.max(iconLp.topMargin, vCenter - iconHeight / 2);
   1306             mIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight);
   1307         }
   1308     }
   1309 
   1310     private class ExpandedActionViewMenuPresenter implements MenuPresenter {
   1311         MenuBuilder mMenu;
   1312         MenuItemImpl mCurrentExpandedItem;
   1313 
   1314         @Override
   1315         public void initForMenu(Context context, MenuBuilder menu) {
   1316             // Clear the expanded action view when menus change.
   1317             if (mMenu != null && mCurrentExpandedItem != null) {
   1318                 mMenu.collapseItemActionView(mCurrentExpandedItem);
   1319             }
   1320             mMenu = menu;
   1321         }
   1322 
   1323         @Override
   1324         public MenuView getMenuView(ViewGroup root) {
   1325             return null;
   1326         }
   1327 
   1328         @Override
   1329         public void updateMenuView(boolean cleared) {
   1330             // Make sure the expanded item we have is still there.
   1331             if (mCurrentExpandedItem != null) {
   1332                 boolean found = false;
   1333 
   1334                 if (mMenu != null) {
   1335                     final int count = mMenu.size();
   1336                     for (int i = 0; i < count; i++) {
   1337                         final MenuItem item = mMenu.getItem(i);
   1338                         if (item == mCurrentExpandedItem) {
   1339                             found = true;
   1340                             break;
   1341                         }
   1342                     }
   1343                 }
   1344 
   1345                 if (!found) {
   1346                     // The item we had expanded disappeared. Collapse.
   1347                     collapseItemActionView(mMenu, mCurrentExpandedItem);
   1348                 }
   1349             }
   1350         }
   1351 
   1352         @Override
   1353         public void setCallback(Callback cb) {
   1354         }
   1355 
   1356         @Override
   1357         public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
   1358             return false;
   1359         }
   1360 
   1361         @Override
   1362         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
   1363         }
   1364 
   1365         @Override
   1366         public boolean flagActionItems() {
   1367             return false;
   1368         }
   1369 
   1370         @Override
   1371         public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
   1372             mExpandedActionView = item.getActionView();
   1373             mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
   1374             mCurrentExpandedItem = item;
   1375             if (mExpandedActionView.getParent() != ActionBarView.this) {
   1376                 addView(mExpandedActionView);
   1377             }
   1378             if (mExpandedHomeLayout.getParent() != ActionBarView.this) {
   1379                 addView(mExpandedHomeLayout);
   1380             }
   1381             mHomeLayout.setVisibility(GONE);
   1382             if (mTitleLayout != null) mTitleLayout.setVisibility(GONE);
   1383             if (mTabScrollView != null) mTabScrollView.setVisibility(GONE);
   1384             if (mSpinner != null) mSpinner.setVisibility(GONE);
   1385             if (mCustomNavView != null) mCustomNavView.setVisibility(GONE);
   1386             requestLayout();
   1387             item.setActionViewExpanded(true);
   1388 
   1389             if (mExpandedActionView instanceof CollapsibleActionView) {
   1390                 ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
   1391             }
   1392 
   1393             return true;
   1394         }
   1395 
   1396         @Override
   1397         public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
   1398             // Do this before detaching the actionview from the hierarchy, in case
   1399             // it needs to dismiss the soft keyboard, etc.
   1400             if (mExpandedActionView instanceof CollapsibleActionView) {
   1401                 ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
   1402             }
   1403 
   1404             removeView(mExpandedActionView);
   1405             removeView(mExpandedHomeLayout);
   1406             mExpandedActionView = null;
   1407             if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) {
   1408                 mHomeLayout.setVisibility(VISIBLE);
   1409             }
   1410             if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
   1411                 if (mTitleLayout == null) {
   1412                     initTitle();
   1413                 } else {
   1414                     mTitleLayout.setVisibility(VISIBLE);
   1415                 }
   1416             }
   1417             if (mTabScrollView != null && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) {
   1418                 mTabScrollView.setVisibility(VISIBLE);
   1419             }
   1420             if (mSpinner != null && mNavigationMode == ActionBar.NAVIGATION_MODE_LIST) {
   1421                 mSpinner.setVisibility(VISIBLE);
   1422             }
   1423             if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
   1424                 mCustomNavView.setVisibility(VISIBLE);
   1425             }
   1426             mExpandedHomeLayout.setIcon(null);
   1427             mCurrentExpandedItem = null;
   1428             requestLayout();
   1429             item.setActionViewExpanded(false);
   1430 
   1431             return true;
   1432         }
   1433 
   1434         @Override
   1435         public int getId() {
   1436             return 0;
   1437         }
   1438 
   1439         @Override
   1440         public Parcelable onSaveInstanceState() {
   1441             return null;
   1442         }
   1443 
   1444         @Override
   1445         public void onRestoreInstanceState(Parcelable state) {
   1446         }
   1447     }
   1448 }
   1449