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