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