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