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