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