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