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