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