2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.actionbarsherlock
.internal
.widget
;
19 import org
.xmlpull
.v1
.XmlPullParser
;
20 import android
.app
.Activity
;
21 import android
.content
.Context
;
22 import android
.content
.pm
.ApplicationInfo
;
23 import android
.content
.pm
.PackageManager
;
24 import android
.content
.pm
.PackageManager
.NameNotFoundException
;
25 import android
.content
.res
.AssetManager
;
26 import android
.content
.res
.Configuration
;
27 import android
.content
.res
.TypedArray
;
28 import android
.content
.res
.XmlResourceParser
;
29 import android
.graphics
.drawable
.Drawable
;
30 import android
.os
.Build
;
31 import android
.os
.Parcel
;
32 import android
.os
.Parcelable
;
33 import android
.text
.TextUtils
;
34 import android
.util
.AttributeSet
;
35 import android
.util
.Log
;
36 import android
.view
.Gravity
;
37 import android
.view
.LayoutInflater
;
38 import android
.view
.MotionEvent
;
39 import android
.view
.View
;
40 import android
.view
.ViewGroup
;
41 import android
.view
.ViewParent
;
42 import android
.view
.accessibility
.AccessibilityEvent
;
43 import android
.widget
.FrameLayout
;
44 import android
.widget
.ImageView
;
45 import android
.widget
.LinearLayout
;
46 import android
.widget
.SpinnerAdapter
;
47 import android
.widget
.TextView
;
49 import com
.actionbarsherlock
.R
;
50 import com
.actionbarsherlock
.app
.ActionBar
;
51 import com
.actionbarsherlock
.app
.ActionBar
.OnNavigationListener
;
52 import com
.actionbarsherlock
.internal
.ActionBarSherlockCompat
;
53 import com
.actionbarsherlock
.internal
.view
.menu
.ActionMenuItem
;
54 import com
.actionbarsherlock
.internal
.view
.menu
.ActionMenuPresenter
;
55 import com
.actionbarsherlock
.internal
.view
.menu
.ActionMenuView
;
56 import com
.actionbarsherlock
.internal
.view
.menu
.MenuBuilder
;
57 import com
.actionbarsherlock
.internal
.view
.menu
.MenuItemImpl
;
58 import com
.actionbarsherlock
.internal
.view
.menu
.MenuPresenter
;
59 import com
.actionbarsherlock
.internal
.view
.menu
.MenuView
;
60 import com
.actionbarsherlock
.internal
.view
.menu
.SubMenuBuilder
;
61 import com
.actionbarsherlock
.view
.CollapsibleActionView
;
62 import com
.actionbarsherlock
.view
.Menu
;
63 import com
.actionbarsherlock
.view
.MenuItem
;
64 import com
.actionbarsherlock
.view
.Window
;
66 import static com
.actionbarsherlock
.internal
.ResourcesCompat
.getResources_getBoolean
;
71 public class ActionBarView
extends AbsActionBarView
{
72 private static final String TAG
= "ActionBarView";
73 private static final boolean DEBUG
= false
;
76 * Display options applied by default
78 public static final int DISPLAY_DEFAULT
= 0;
81 * Display options that require re-layout as opposed to a simple invalidate
83 private static final int DISPLAY_RELAYOUT_MASK
=
84 ActionBar
.DISPLAY_SHOW_HOME
|
85 ActionBar
.DISPLAY_USE_LOGO
|
86 ActionBar
.DISPLAY_HOME_AS_UP
|
87 ActionBar
.DISPLAY_SHOW_CUSTOM
|
88 ActionBar
.DISPLAY_SHOW_TITLE
;
90 private static final int DEFAULT_CUSTOM_GRAVITY
= Gravity
.LEFT
| Gravity
.CENTER_VERTICAL
;
92 private int mNavigationMode
;
93 private int mDisplayOptions
= -1;
94 private CharSequence mTitle
;
95 private CharSequence mSubtitle
;
96 private Drawable mIcon
;
97 private Drawable mLogo
;
99 private HomeView mHomeLayout
;
100 private HomeView mExpandedHomeLayout
;
101 private LinearLayout mTitleLayout
;
102 private TextView mTitleView
;
103 private TextView mSubtitleView
;
104 private View mTitleUpView
;
106 private IcsSpinner mSpinner
;
107 private IcsLinearLayout mListNavLayout
;
108 private ScrollingTabContainerView mTabScrollView
;
109 private View mCustomNavView
;
110 private IcsProgressBar mProgressView
;
111 private IcsProgressBar mIndeterminateProgressView
;
113 private int mProgressBarPadding
;
114 private int mItemPadding
;
116 private int mTitleStyleRes
;
117 private int mSubtitleStyleRes
;
118 private int mProgressStyle
;
119 private int mIndeterminateProgressStyle
;
121 private boolean mUserTitle
;
122 private boolean mIncludeTabs
;
123 private boolean mIsCollapsable
;
124 private boolean mIsCollapsed
;
126 private MenuBuilder mOptionsMenu
;
128 private ActionBarContextView mContextView
;
130 private ActionMenuItem mLogoNavItem
;
132 private SpinnerAdapter mSpinnerAdapter
;
133 private OnNavigationListener mCallback
;
135 //UNUSED private Runnable mTabSelector;
137 private ExpandedActionViewMenuPresenter mExpandedMenuPresenter
;
138 View mExpandedActionView
;
140 Window
.Callback mWindowCallback
;
142 @SuppressWarnings("rawtypes")
143 private final IcsAdapterView
.OnItemSelectedListener mNavItemSelectedListener
=
144 new IcsAdapterView
.OnItemSelectedListener() {
145 public void onItemSelected(IcsAdapterView parent
, View view
, int position
, long id
) {
146 if (mCallback
!= null
) {
147 mCallback
.onNavigationItemSelected(position
, id
);
150 public void onNothingSelected(IcsAdapterView parent
) {
155 private final OnClickListener mExpandedActionViewUpListener
= new OnClickListener() {
157 public void onClick(View v
) {
158 final MenuItemImpl item
= mExpandedMenuPresenter
.mCurrentExpandedItem
;
160 item
.collapseActionView();
165 private final OnClickListener mUpClickListener
= new OnClickListener() {
166 public void onClick(View v
) {
167 mWindowCallback
.onMenuItemSelected(Window
.FEATURE_OPTIONS_PANEL
, mLogoNavItem
);
171 public ActionBarView(Context context
, AttributeSet attrs
) {
172 super(context
, attrs
);
174 // Background is always provided by the container.
175 setBackgroundResource(0);
177 TypedArray a
= context
.obtainStyledAttributes(attrs
, R
.styleable
.SherlockActionBar
,
178 R
.attr
.actionBarStyle
, 0);
180 ApplicationInfo appInfo
= context
.getApplicationInfo();
181 PackageManager pm
= context
.getPackageManager();
182 mNavigationMode
= a
.getInt(R
.styleable
.SherlockActionBar_navigationMode
,
183 ActionBar
.NAVIGATION_MODE_STANDARD
);
184 mTitle
= a
.getText(R
.styleable
.SherlockActionBar_title
);
185 mSubtitle
= a
.getText(R
.styleable
.SherlockActionBar_subtitle
);
187 mLogo
= a
.getDrawable(R
.styleable
.SherlockActionBar_logo
);
189 if (Build
.VERSION
.SDK_INT
< Build
.VERSION_CODES
.HONEYCOMB
) {
190 if (context
instanceof Activity
) {
191 //Even though native methods existed in API 9 and 10 they don't work
192 //so just parse the manifest to look for the logo pre-Honeycomb
193 final int resId
= loadLogoFromManifest((Activity
) context
);
195 mLogo
= context
.getResources().getDrawable(resId
);
199 if (context
instanceof Activity
) {
201 mLogo
= pm
.getActivityLogo(((Activity
) context
).getComponentName());
202 } catch (NameNotFoundException e
) {
203 Log
.e(TAG
, "Activity component name not found!", e
);
207 mLogo
= appInfo
.loadLogo(pm
);
212 mIcon
= a
.getDrawable(R
.styleable
.SherlockActionBar_icon
);
214 if (context
instanceof Activity
) {
216 mIcon
= pm
.getActivityIcon(((Activity
) context
).getComponentName());
217 } catch (NameNotFoundException e
) {
218 Log
.e(TAG
, "Activity component name not found!", e
);
222 mIcon
= appInfo
.loadIcon(pm
);
226 final LayoutInflater inflater
= LayoutInflater
.from(context
);
228 final int homeResId
= a
.getResourceId(
229 R
.styleable
.SherlockActionBar_homeLayout
,
230 R
.layout
.abs__action_bar_home
);
232 mHomeLayout
= (HomeView
) inflater
.inflate(homeResId
, this, false
);
234 mExpandedHomeLayout
= (HomeView
) inflater
.inflate(homeResId
, this, false
);
235 mExpandedHomeLayout
.setUp(true
);
236 mExpandedHomeLayout
.setOnClickListener(mExpandedActionViewUpListener
);
237 mExpandedHomeLayout
.setContentDescription(getResources().getText(
238 R
.string
.abs__action_bar_up_description
));
240 mTitleStyleRes
= a
.getResourceId(R
.styleable
.SherlockActionBar_titleTextStyle
, 0);
241 mSubtitleStyleRes
= a
.getResourceId(R
.styleable
.SherlockActionBar_subtitleTextStyle
, 0);
242 mProgressStyle
= a
.getResourceId(R
.styleable
.SherlockActionBar_progressBarStyle
, 0);
243 mIndeterminateProgressStyle
= a
.getResourceId(
244 R
.styleable
.SherlockActionBar_indeterminateProgressStyle
, 0);
246 mProgressBarPadding
= a
.getDimensionPixelOffset(R
.styleable
.SherlockActionBar_progressBarPadding
, 0);
247 mItemPadding
= a
.getDimensionPixelOffset(R
.styleable
.SherlockActionBar_itemPadding
, 0);
249 setDisplayOptions(a
.getInt(R
.styleable
.SherlockActionBar_displayOptions
, DISPLAY_DEFAULT
));
251 final int customNavId
= a
.getResourceId(R
.styleable
.SherlockActionBar_customNavigationLayout
, 0);
252 if (customNavId
!= 0) {
253 mCustomNavView
= inflater
.inflate(customNavId
, this, false
);
254 mNavigationMode
= ActionBar
.NAVIGATION_MODE_STANDARD
;
255 setDisplayOptions(mDisplayOptions
| ActionBar
.DISPLAY_SHOW_CUSTOM
);
258 mContentHeight
= a
.getLayoutDimension(R
.styleable
.SherlockActionBar_height
, 0);
262 mLogoNavItem
= new ActionMenuItem(context
, 0, android
.R
.id
.home
, 0, 0, mTitle
);
263 mHomeLayout
.setOnClickListener(mUpClickListener
);
264 mHomeLayout
.setClickable(true
);
265 mHomeLayout
.setFocusable(true
);
269 * Attempt to programmatically load the logo from the manifest file of an
270 * activity by using an XML pull parser. This should allow us to read the
271 * logo attribute regardless of the platform it is being run on.
273 * @param activity Activity instance.
274 * @return Logo resource ID.
276 private static int loadLogoFromManifest(Activity activity
) {
279 final String thisPackage
= activity
.getClass().getName();
280 if (DEBUG
) Log
.i(TAG
, "Parsing AndroidManifest.xml for " + thisPackage
);
282 final String packageName
= activity
.getApplicationInfo().packageName
;
283 final AssetManager am
= activity
.createPackageContext(packageName
, 0).getAssets();
284 final XmlResourceParser xml
= am
.openXmlResourceParser("AndroidManifest.xml");
286 int eventType
= xml
.getEventType();
287 while (eventType
!= XmlPullParser
.END_DOCUMENT
) {
288 if (eventType
== XmlPullParser
.START_TAG
) {
289 String name
= xml
.getName();
291 if ("application".equals(name
)) {
292 //Check if the <application> has the attribute
293 if (DEBUG
) Log
.d(TAG
, "Got <application>");
295 for (int i
= xml
.getAttributeCount() - 1; i
>= 0; i
--) {
296 if (DEBUG
) Log
.d(TAG
, xml
.getAttributeName(i
) + ": " + xml
.getAttributeValue(i
));
298 if ("logo".equals(xml
.getAttributeName(i
))) {
299 logo
= xml
.getAttributeResourceValue(i
, 0);
300 break; //out of for loop
303 } else if ("activity".equals(name
)) {
304 //Check if the <activity> is us and has the attribute
305 if (DEBUG
) Log
.d(TAG
, "Got <activity>");
306 Integer activityLogo
= null
;
307 String activityPackage
= null
;
308 boolean isOurActivity
= false
;
310 for (int i
= xml
.getAttributeCount() - 1; i
>= 0; i
--) {
311 if (DEBUG
) Log
.d(TAG
, xml
.getAttributeName(i
) + ": " + xml
.getAttributeValue(i
));
313 //We need both uiOptions and name attributes
314 String attrName
= xml
.getAttributeName(i
);
315 if ("logo".equals(attrName
)) {
316 activityLogo
= xml
.getAttributeResourceValue(i
, 0);
317 } else if ("name".equals(attrName
)) {
318 activityPackage
= ActionBarSherlockCompat
.cleanActivityName(packageName
, xml
.getAttributeValue(i
));
319 if (!thisPackage
.equals(activityPackage
)) {
320 break; //on to the next
322 isOurActivity
= true
;
325 //Make sure we have both attributes before processing
326 if ((activityLogo
!= null
) && (activityPackage
!= null
)) {
327 //Our activity, logo specified, override with our value
328 logo
= activityLogo
.intValue();
332 //If we matched our activity but it had no logo don't
333 //do any more processing of the manifest
338 eventType
= xml
.nextToken();
340 } catch (Exception e
) {
343 if (DEBUG
) Log
.i(TAG
, "Returning " + Integer
.toHexString(logo
));
348 * Must be public so we can dispatch pre-2.2 via ActionBarImpl.
351 public void onConfigurationChanged(Configuration newConfig
) {
352 super.onConfigurationChanged(newConfig
);
355 mSubtitleView
= null
;
357 if (mTitleLayout
!= null
&& mTitleLayout
.getParent() == this) {
358 removeView(mTitleLayout
);
361 if ((mDisplayOptions
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0) {
365 if (mTabScrollView
!= null
&& mIncludeTabs
) {
366 ViewGroup
.LayoutParams lp
= mTabScrollView
.getLayoutParams();
368 lp
.width
= LayoutParams
.WRAP_CONTENT
;
369 lp
.height
= LayoutParams
.MATCH_PARENT
;
371 mTabScrollView
.setAllowCollapse(true
);
376 * Set the window callback used to invoke menu items; used for dispatching home button presses.
377 * @param cb Window callback to dispatch to
379 public void setWindowCallback(Window
.Callback cb
) {
380 mWindowCallback
= cb
;
384 public void onDetachedFromWindow() {
385 super.onDetachedFromWindow();
386 //UNUSED removeCallbacks(mTabSelector);
387 if (mActionMenuPresenter
!= null
) {
388 mActionMenuPresenter
.hideOverflowMenu();
389 mActionMenuPresenter
.hideSubMenus();
394 public boolean shouldDelayChildPressedState() {
398 public void initProgress() {
399 mProgressView
= new IcsProgressBar(mContext
, null
, 0, mProgressStyle
);
400 mProgressView
.setId(R
.id
.abs__progress_horizontal
);
401 mProgressView
.setMax(10000);
402 addView(mProgressView
);
405 public void initIndeterminateProgress() {
406 mIndeterminateProgressView
= new IcsProgressBar(mContext
, null
, 0, mIndeterminateProgressStyle
);
407 mIndeterminateProgressView
.setId(R
.id
.abs__progress_circular
);
408 addView(mIndeterminateProgressView
);
412 public void setSplitActionBar(boolean splitActionBar
) {
413 if (mSplitActionBar
!= splitActionBar
) {
414 if (mMenuView
!= null
) {
415 final ViewGroup oldParent
= (ViewGroup
) mMenuView
.getParent();
416 if (oldParent
!= null
) {
417 oldParent
.removeView(mMenuView
);
419 if (splitActionBar
) {
420 if (mSplitView
!= null
) {
421 mSplitView
.addView(mMenuView
);
427 if (mSplitView
!= null
) {
428 mSplitView
.setVisibility(splitActionBar ? VISIBLE
: GONE
);
430 super.setSplitActionBar(splitActionBar
);
434 public boolean isSplitActionBar() {
435 return mSplitActionBar
;
438 public boolean hasEmbeddedTabs() {
442 public void setEmbeddedTabView(ScrollingTabContainerView tabs
) {
443 if (mTabScrollView
!= null
) {
444 removeView(mTabScrollView
);
446 mTabScrollView
= tabs
;
447 mIncludeTabs
= tabs
!= null
;
448 if (mIncludeTabs
&& mNavigationMode
== ActionBar
.NAVIGATION_MODE_TABS
) {
449 addView(mTabScrollView
);
450 ViewGroup
.LayoutParams lp
= mTabScrollView
.getLayoutParams();
451 lp
.width
= LayoutParams
.WRAP_CONTENT
;
452 lp
.height
= LayoutParams
.MATCH_PARENT
;
453 tabs
.setAllowCollapse(true
);
457 public void setCallback(OnNavigationListener callback
) {
458 mCallback
= callback
;
461 public void setMenu(Menu menu
, MenuPresenter
.Callback cb
) {
462 if (menu
== mOptionsMenu
) return;
464 if (mOptionsMenu
!= null
) {
465 mOptionsMenu
.removeMenuPresenter(mActionMenuPresenter
);
466 mOptionsMenu
.removeMenuPresenter(mExpandedMenuPresenter
);
469 MenuBuilder builder
= (MenuBuilder
) menu
;
470 mOptionsMenu
= builder
;
471 if (mMenuView
!= null
) {
472 final ViewGroup oldParent
= (ViewGroup
) mMenuView
.getParent();
473 if (oldParent
!= null
) {
474 oldParent
.removeView(mMenuView
);
477 if (mActionMenuPresenter
== null
) {
478 mActionMenuPresenter
= new ActionMenuPresenter(mContext
);
479 mActionMenuPresenter
.setCallback(cb
);
480 mActionMenuPresenter
.setId(R
.id
.abs__action_menu_presenter
);
481 mExpandedMenuPresenter
= new ExpandedActionViewMenuPresenter();
484 ActionMenuView menuView
;
485 final LayoutParams layoutParams
= new LayoutParams(LayoutParams
.WRAP_CONTENT
,
486 LayoutParams
.MATCH_PARENT
);
487 if (!mSplitActionBar
) {
488 mActionMenuPresenter
.setExpandedActionViewsExclusive(
489 getResources_getBoolean(getContext(),
490 R
.bool
.abs__action_bar_expanded_action_views_exclusive
));
491 configPresenters(builder
);
492 menuView
= (ActionMenuView
) mActionMenuPresenter
.getMenuView(this);
493 final ViewGroup oldParent
= (ViewGroup
) menuView
.getParent();
494 if (oldParent
!= null
&& oldParent
!= this) {
495 oldParent
.removeView(menuView
);
497 addView(menuView
, layoutParams
);
499 mActionMenuPresenter
.setExpandedActionViewsExclusive(false
);
500 // Allow full screen width in split mode.
501 mActionMenuPresenter
.setWidthLimit(
502 getContext().getResources().getDisplayMetrics().widthPixels
, true
);
503 // No limit to the item count; use whatever will fit.
504 mActionMenuPresenter
.setItemLimit(Integer
.MAX_VALUE
);
505 // Span the whole width
506 layoutParams
.width
= LayoutParams
.MATCH_PARENT
;
507 configPresenters(builder
);
508 menuView
= (ActionMenuView
) mActionMenuPresenter
.getMenuView(this);
509 if (mSplitView
!= null
) {
510 final ViewGroup oldParent
= (ViewGroup
) menuView
.getParent();
511 if (oldParent
!= null
&& oldParent
!= mSplitView
) {
512 oldParent
.removeView(menuView
);
514 menuView
.setVisibility(getAnimatedVisibility());
515 mSplitView
.addView(menuView
, layoutParams
);
517 // We'll add this later if we missed it this time.
518 menuView
.setLayoutParams(layoutParams
);
521 mMenuView
= menuView
;
524 private void configPresenters(MenuBuilder builder
) {
525 if (builder
!= null
) {
526 builder
.addMenuPresenter(mActionMenuPresenter
);
527 builder
.addMenuPresenter(mExpandedMenuPresenter
);
529 mActionMenuPresenter
.initForMenu(mContext
, null
);
530 mExpandedMenuPresenter
.initForMenu(mContext
, null
);
531 mActionMenuPresenter
.updateMenuView(true
);
532 mExpandedMenuPresenter
.updateMenuView(true
);
536 public boolean hasExpandedActionView() {
537 return mExpandedMenuPresenter
!= null
&&
538 mExpandedMenuPresenter
.mCurrentExpandedItem
!= null
;
541 public void collapseActionView() {
542 final MenuItemImpl item
= mExpandedMenuPresenter
== null ? null
:
543 mExpandedMenuPresenter
.mCurrentExpandedItem
;
545 item
.collapseActionView();
549 public void setCustomNavigationView(View view
) {
550 final boolean showCustom
= (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_CUSTOM
) != 0;
551 if (mCustomNavView
!= null
&& showCustom
) {
552 removeView(mCustomNavView
);
554 mCustomNavView
= view
;
555 if (mCustomNavView
!= null
&& showCustom
) {
556 addView(mCustomNavView
);
560 public CharSequence
getTitle() {
565 * Set the action bar title. This will always replace or override window titles.
566 * @param title Title to set
568 * @see #setWindowTitle(CharSequence)
570 public void setTitle(CharSequence title
) {
576 * Set the window title. A window title will always be replaced or overridden by a user title.
577 * @param title Title to set
579 * @see #setTitle(CharSequence)
581 public void setWindowTitle(CharSequence title
) {
587 private void setTitleImpl(CharSequence title
) {
589 if (mTitleView
!= null
) {
590 mTitleView
.setText(title
);
591 final boolean visible
= mExpandedActionView
== null
&&
592 (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0 &&
593 (!TextUtils
.isEmpty(mTitle
) || !TextUtils
.isEmpty(mSubtitle
));
594 mTitleLayout
.setVisibility(visible ? VISIBLE
: GONE
);
596 if (mLogoNavItem
!= null
) {
597 mLogoNavItem
.setTitle(title
);
601 public CharSequence
getSubtitle() {
605 public void setSubtitle(CharSequence subtitle
) {
606 mSubtitle
= subtitle
;
607 if (mSubtitleView
!= null
) {
608 mSubtitleView
.setText(subtitle
);
609 mSubtitleView
.setVisibility(subtitle
!= null ? VISIBLE
: GONE
);
610 final boolean visible
= mExpandedActionView
== null
&&
611 (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0 &&
612 (!TextUtils
.isEmpty(mTitle
) || !TextUtils
.isEmpty(mSubtitle
));
613 mTitleLayout
.setVisibility(visible ? VISIBLE
: GONE
);
617 public void setHomeButtonEnabled(boolean enable
) {
618 mHomeLayout
.setEnabled(enable
);
619 mHomeLayout
.setFocusable(enable
);
620 // Make sure the home button has an accurate content description for accessibility.
622 mHomeLayout
.setContentDescription(null
);
623 } else if ((mDisplayOptions
& ActionBar
.DISPLAY_HOME_AS_UP
) != 0) {
624 mHomeLayout
.setContentDescription(mContext
.getResources().getText(
625 R
.string
.abs__action_bar_up_description
));
627 mHomeLayout
.setContentDescription(mContext
.getResources().getText(
628 R
.string
.abs__action_bar_home_description
));
632 public void setDisplayOptions(int options
) {
633 final int flagsChanged
= mDisplayOptions
== -1 ?
-1 : options ^ mDisplayOptions
;
634 mDisplayOptions
= options
;
636 if ((flagsChanged
& DISPLAY_RELAYOUT_MASK
) != 0) {
637 final boolean showHome
= (options
& ActionBar
.DISPLAY_SHOW_HOME
) != 0;
638 final int vis
= showHome
&& mExpandedActionView
== null ? VISIBLE
: GONE
;
639 mHomeLayout
.setVisibility(vis
);
641 if ((flagsChanged
& ActionBar
.DISPLAY_HOME_AS_UP
) != 0) {
642 final boolean setUp
= (options
& ActionBar
.DISPLAY_HOME_AS_UP
) != 0;
643 mHomeLayout
.setUp(setUp
);
645 // Showing home as up implicitly enables interaction with it.
646 // In honeycomb it was always enabled, so make this transition
647 // a bit easier for developers in the common case.
648 // (It would be silly to show it as up without responding to it.)
650 setHomeButtonEnabled(true
);
654 if ((flagsChanged
& ActionBar
.DISPLAY_USE_LOGO
) != 0) {
655 final boolean logoVis
= mLogo
!= null
&& (options
& ActionBar
.DISPLAY_USE_LOGO
) != 0;
656 mHomeLayout
.setIcon(logoVis ? mLogo
: mIcon
);
659 if ((flagsChanged
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0) {
660 if ((options
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0) {
663 removeView(mTitleLayout
);
667 if (mTitleLayout
!= null
&& (flagsChanged
&
668 (ActionBar
.DISPLAY_HOME_AS_UP
| ActionBar
.DISPLAY_SHOW_HOME
)) != 0) {
669 final boolean homeAsUp
= (mDisplayOptions
& ActionBar
.DISPLAY_HOME_AS_UP
) != 0;
670 mTitleUpView
.setVisibility(!showHome ?
(homeAsUp ? VISIBLE
: INVISIBLE
) : GONE
);
671 mTitleLayout
.setEnabled(!showHome
&& homeAsUp
);
674 if ((flagsChanged
& ActionBar
.DISPLAY_SHOW_CUSTOM
) != 0 && mCustomNavView
!= null
) {
675 if ((options
& ActionBar
.DISPLAY_SHOW_CUSTOM
) != 0) {
676 addView(mCustomNavView
);
678 removeView(mCustomNavView
);
687 // Make sure the home button has an accurate content description for accessibility.
688 if (!mHomeLayout
.isEnabled()) {
689 mHomeLayout
.setContentDescription(null
);
690 } else if ((options
& ActionBar
.DISPLAY_HOME_AS_UP
) != 0) {
691 mHomeLayout
.setContentDescription(mContext
.getResources().getText(
692 R
.string
.abs__action_bar_up_description
));
694 mHomeLayout
.setContentDescription(mContext
.getResources().getText(
695 R
.string
.abs__action_bar_home_description
));
699 public void setIcon(Drawable icon
) {
702 ((mDisplayOptions
& ActionBar
.DISPLAY_USE_LOGO
) == 0 || mLogo
== null
)) {
703 mHomeLayout
.setIcon(icon
);
707 public void setIcon(int resId
) {
708 setIcon(mContext
.getResources().getDrawable(resId
));
711 public void setLogo(Drawable logo
) {
713 if (logo
!= null
&& (mDisplayOptions
& ActionBar
.DISPLAY_USE_LOGO
) != 0) {
714 mHomeLayout
.setIcon(logo
);
718 public void setLogo(int resId
) {
719 setLogo(mContext
.getResources().getDrawable(resId
));
722 public void setNavigationMode(int mode
) {
723 final int oldMode
= mNavigationMode
;
724 if (mode
!= oldMode
) {
726 case ActionBar
.NAVIGATION_MODE_LIST
:
727 if (mListNavLayout
!= null
) {
728 removeView(mListNavLayout
);
731 case ActionBar
.NAVIGATION_MODE_TABS
:
732 if (mTabScrollView
!= null
&& mIncludeTabs
) {
733 removeView(mTabScrollView
);
738 case ActionBar
.NAVIGATION_MODE_LIST
:
739 if (mSpinner
== null
) {
740 mSpinner
= new IcsSpinner(mContext
, null
,
741 R
.attr
.actionDropDownStyle
);
742 mListNavLayout
= (IcsLinearLayout
) LayoutInflater
.from(mContext
)
743 .inflate(R
.layout
.abs__action_bar_tab_bar_view
, null
);
744 LinearLayout
.LayoutParams params
= new LinearLayout
.LayoutParams(
745 LayoutParams
.WRAP_CONTENT
, LayoutParams
.MATCH_PARENT
);
746 params
.gravity
= Gravity
.CENTER
;
747 mListNavLayout
.addView(mSpinner
, params
);
749 if (mSpinner
.getAdapter() != mSpinnerAdapter
) {
750 mSpinner
.setAdapter(mSpinnerAdapter
);
752 mSpinner
.setOnItemSelectedListener(mNavItemSelectedListener
);
753 addView(mListNavLayout
);
755 case ActionBar
.NAVIGATION_MODE_TABS
:
756 if (mTabScrollView
!= null
&& mIncludeTabs
) {
757 addView(mTabScrollView
);
761 mNavigationMode
= mode
;
766 public void setDropdownAdapter(SpinnerAdapter adapter
) {
767 mSpinnerAdapter
= adapter
;
768 if (mSpinner
!= null
) {
769 mSpinner
.setAdapter(adapter
);
773 public SpinnerAdapter
getDropdownAdapter() {
774 return mSpinnerAdapter
;
777 public void setDropdownSelectedPosition(int position
) {
778 mSpinner
.setSelection(position
);
781 public int getDropdownSelectedPosition() {
782 return mSpinner
.getSelectedItemPosition();
785 public View
getCustomNavigationView() {
786 return mCustomNavView
;
789 public int getNavigationMode() {
790 return mNavigationMode
;
793 public int getDisplayOptions() {
794 return mDisplayOptions
;
798 protected ViewGroup
.LayoutParams
generateDefaultLayoutParams() {
799 // Used by custom nav views if they don't supply layout params. Everything else
800 // added to an ActionBarView should have them already.
801 return new ActionBar
.LayoutParams(DEFAULT_CUSTOM_GRAVITY
);
805 protected void onFinishInflate() {
806 super.onFinishInflate();
808 addView(mHomeLayout
);
810 if (mCustomNavView
!= null
&& (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_CUSTOM
) != 0) {
811 final ViewParent parent
= mCustomNavView
.getParent();
812 if (parent
!= this) {
813 if (parent
instanceof ViewGroup
) {
814 ((ViewGroup
) parent
).removeView(mCustomNavView
);
816 addView(mCustomNavView
);
821 private void initTitle() {
822 if (mTitleLayout
== null
) {
823 LayoutInflater inflater
= LayoutInflater
.from(getContext());
824 mTitleLayout
= (LinearLayout
) inflater
.inflate(R
.layout
.abs__action_bar_title_item
,
826 mTitleView
= (TextView
) mTitleLayout
.findViewById(R
.id
.abs__action_bar_title
);
827 mSubtitleView
= (TextView
) mTitleLayout
.findViewById(R
.id
.abs__action_bar_subtitle
);
828 mTitleUpView
= mTitleLayout
.findViewById(R
.id
.abs__up
);
830 mTitleLayout
.setOnClickListener(mUpClickListener
);
832 if (mTitleStyleRes
!= 0) {
833 mTitleView
.setTextAppearance(mContext
, mTitleStyleRes
);
835 if (mTitle
!= null
) {
836 mTitleView
.setText(mTitle
);
839 if (mSubtitleStyleRes
!= 0) {
840 mSubtitleView
.setTextAppearance(mContext
, mSubtitleStyleRes
);
842 if (mSubtitle
!= null
) {
843 mSubtitleView
.setText(mSubtitle
);
844 mSubtitleView
.setVisibility(VISIBLE
);
847 final boolean homeAsUp
= (mDisplayOptions
& ActionBar
.DISPLAY_HOME_AS_UP
) != 0;
848 final boolean showHome
= (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_HOME
) != 0;
849 mTitleUpView
.setVisibility(!showHome ?
(homeAsUp ? VISIBLE
: INVISIBLE
) : GONE
);
850 mTitleLayout
.setEnabled(homeAsUp
&& !showHome
);
853 addView(mTitleLayout
);
854 if (mExpandedActionView
!= null
||
855 (TextUtils
.isEmpty(mTitle
) && TextUtils
.isEmpty(mSubtitle
))) {
856 // Don't show while in expanded mode or with empty text
857 mTitleLayout
.setVisibility(GONE
);
861 public void setContextView(ActionBarContextView view
) {
865 public void setCollapsable(boolean collapsable
) {
866 mIsCollapsable
= collapsable
;
869 public boolean isCollapsed() {
874 protected void onMeasure(int widthMeasureSpec
, int heightMeasureSpec
) {
875 final int childCount
= getChildCount();
876 if (mIsCollapsable
) {
877 int visibleChildren
= 0;
878 for (int i
= 0; i
< childCount
; i
++) {
879 final View child
= getChildAt(i
);
880 if (child
.getVisibility() != GONE
&&
881 !(child
== mMenuView
&& mMenuView
.getChildCount() == 0)) {
886 if (visibleChildren
== 0) {
887 // No size for an empty action bar when collapsable.
888 setMeasuredDimension(0, 0);
893 mIsCollapsed
= false
;
895 int widthMode
= MeasureSpec
.getMode(widthMeasureSpec
);
896 if (widthMode
!= MeasureSpec
.EXACTLY
) {
897 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
898 "with android:layout_width=\"match_parent\" (or fill_parent)");
901 int heightMode
= MeasureSpec
.getMode(heightMeasureSpec
);
902 if (heightMode
!= MeasureSpec
.AT_MOST
) {
903 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
904 "with android:layout_height=\"wrap_content\"");
907 int contentWidth
= MeasureSpec
.getSize(widthMeasureSpec
);
909 int maxHeight
= mContentHeight
> 0 ?
910 mContentHeight
: MeasureSpec
.getSize(heightMeasureSpec
);
912 final int verticalPadding
= getPaddingTop() + getPaddingBottom();
913 final int paddingLeft
= getPaddingLeft();
914 final int paddingRight
= getPaddingRight();
915 final int height
= maxHeight
- verticalPadding
;
916 final int childSpecHeight
= MeasureSpec
.makeMeasureSpec(height
, MeasureSpec
.AT_MOST
);
918 int availableWidth
= contentWidth
- paddingLeft
- paddingRight
;
919 int leftOfCenter
= availableWidth
/ 2;
920 int rightOfCenter
= leftOfCenter
;
922 HomeView homeLayout
= mExpandedActionView
!= null ? mExpandedHomeLayout
: mHomeLayout
;
924 if (homeLayout
.getVisibility() != GONE
) {
925 final ViewGroup
.LayoutParams lp
= homeLayout
.getLayoutParams();
928 homeWidthSpec
= MeasureSpec
.makeMeasureSpec(availableWidth
, MeasureSpec
.AT_MOST
);
930 homeWidthSpec
= MeasureSpec
.makeMeasureSpec(lp
.width
, MeasureSpec
.EXACTLY
);
932 homeLayout
.measure(homeWidthSpec
,
933 MeasureSpec
.makeMeasureSpec(height
, MeasureSpec
.EXACTLY
));
934 final int homeWidth
= homeLayout
.getMeasuredWidth() + homeLayout
.getLeftOffset();
935 availableWidth
= Math
.max(0, availableWidth
- homeWidth
);
936 leftOfCenter
= Math
.max(0, availableWidth
- homeWidth
);
939 if (mMenuView
!= null
&& mMenuView
.getParent() == this) {
940 availableWidth
= measureChildView(mMenuView
, availableWidth
,
942 rightOfCenter
= Math
.max(0, rightOfCenter
- mMenuView
.getMeasuredWidth());
945 if (mIndeterminateProgressView
!= null
&&
946 mIndeterminateProgressView
.getVisibility() != GONE
) {
947 availableWidth
= measureChildView(mIndeterminateProgressView
, availableWidth
,
949 rightOfCenter
= Math
.max(0,
950 rightOfCenter
- mIndeterminateProgressView
.getMeasuredWidth());
953 final boolean showTitle
= mTitleLayout
!= null
&& mTitleLayout
.getVisibility() != GONE
&&
954 (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0;
956 if (mExpandedActionView
== null
) {
957 switch (mNavigationMode
) {
958 case ActionBar
.NAVIGATION_MODE_LIST
:
959 if (mListNavLayout
!= null
) {
960 final int itemPaddingSize
= showTitle ? mItemPadding
* 2 : mItemPadding
;
961 availableWidth
= Math
.max(0, availableWidth
- itemPaddingSize
);
962 leftOfCenter
= Math
.max(0, leftOfCenter
- itemPaddingSize
);
963 mListNavLayout
.measure(
964 MeasureSpec
.makeMeasureSpec(availableWidth
, MeasureSpec
.AT_MOST
),
965 MeasureSpec
.makeMeasureSpec(height
, MeasureSpec
.EXACTLY
));
966 final int listNavWidth
= mListNavLayout
.getMeasuredWidth();
967 availableWidth
= Math
.max(0, availableWidth
- listNavWidth
);
968 leftOfCenter
= Math
.max(0, leftOfCenter
- listNavWidth
);
971 case ActionBar
.NAVIGATION_MODE_TABS
:
972 if (mTabScrollView
!= null
) {
973 final int itemPaddingSize
= showTitle ? mItemPadding
* 2 : mItemPadding
;
974 availableWidth
= Math
.max(0, availableWidth
- itemPaddingSize
);
975 leftOfCenter
= Math
.max(0, leftOfCenter
- itemPaddingSize
);
976 mTabScrollView
.measure(
977 MeasureSpec
.makeMeasureSpec(availableWidth
, MeasureSpec
.AT_MOST
),
978 MeasureSpec
.makeMeasureSpec(height
, MeasureSpec
.EXACTLY
));
979 final int tabWidth
= mTabScrollView
.getMeasuredWidth();
980 availableWidth
= Math
.max(0, availableWidth
- tabWidth
);
981 leftOfCenter
= Math
.max(0, leftOfCenter
- tabWidth
);
987 View customView
= null
;
988 if (mExpandedActionView
!= null
) {
989 customView
= mExpandedActionView
;
990 } else if ((mDisplayOptions
& ActionBar
.DISPLAY_SHOW_CUSTOM
) != 0 &&
991 mCustomNavView
!= null
) {
992 customView
= mCustomNavView
;
995 if (customView
!= null
) {
996 final ViewGroup
.LayoutParams lp
= generateLayoutParams(customView
.getLayoutParams());
997 final ActionBar
.LayoutParams ablp
= lp
instanceof ActionBar
.LayoutParams ?
998 (ActionBar
.LayoutParams
) lp
: null
;
1000 int horizontalMargin
= 0;
1001 int verticalMargin
= 0;
1003 horizontalMargin
= ablp
.leftMargin
+ ablp
.rightMargin
;
1004 verticalMargin
= ablp
.topMargin
+ ablp
.bottomMargin
;
1007 // If the action bar is wrapping to its content height, don't allow a custom
1008 // view to MATCH_PARENT.
1009 int customNavHeightMode
;
1010 if (mContentHeight
<= 0) {
1011 customNavHeightMode
= MeasureSpec
.AT_MOST
;
1013 customNavHeightMode
= lp
.height
!= LayoutParams
.WRAP_CONTENT ?
1014 MeasureSpec
.EXACTLY
: MeasureSpec
.AT_MOST
;
1016 final int customNavHeight
= Math
.max(0,
1017 (lp
.height
>= 0 ? Math
.min(lp
.height
, height
) : height
) - verticalMargin
);
1019 final int customNavWidthMode
= lp
.width
!= LayoutParams
.WRAP_CONTENT ?
1020 MeasureSpec
.EXACTLY
: MeasureSpec
.AT_MOST
;
1021 int customNavWidth
= Math
.max(0,
1022 (lp
.width
>= 0 ? Math
.min(lp
.width
, availableWidth
) : availableWidth
)
1023 - horizontalMargin
);
1024 final int hgrav
= (ablp
!= null ? ablp
.gravity
: DEFAULT_CUSTOM_GRAVITY
) &
1025 Gravity
.HORIZONTAL_GRAVITY_MASK
;
1027 // Centering a custom view is treated specially; we try to center within the whole
1028 // action bar rather than in the available space.
1029 if (hgrav
== Gravity
.CENTER_HORIZONTAL
&& lp
.width
== LayoutParams
.MATCH_PARENT
) {
1030 customNavWidth
= Math
.min(leftOfCenter
, rightOfCenter
) * 2;
1034 MeasureSpec
.makeMeasureSpec(customNavWidth
, customNavWidthMode
),
1035 MeasureSpec
.makeMeasureSpec(customNavHeight
, customNavHeightMode
));
1036 availableWidth
-= horizontalMargin
+ customView
.getMeasuredWidth();
1039 if (mExpandedActionView
== null
&& showTitle
) {
1040 availableWidth
= measureChildView(mTitleLayout
, availableWidth
,
1041 MeasureSpec
.makeMeasureSpec(mContentHeight
, MeasureSpec
.EXACTLY
), 0);
1042 leftOfCenter
= Math
.max(0, leftOfCenter
- mTitleLayout
.getMeasuredWidth());
1045 if (mContentHeight
<= 0) {
1046 int measuredHeight
= 0;
1047 for (int i
= 0; i
< childCount
; i
++) {
1048 View v
= getChildAt(i
);
1049 int paddedViewHeight
= v
.getMeasuredHeight() + verticalPadding
;
1050 if (paddedViewHeight
> measuredHeight
) {
1051 measuredHeight
= paddedViewHeight
;
1054 setMeasuredDimension(contentWidth
, measuredHeight
);
1056 setMeasuredDimension(contentWidth
, maxHeight
);
1059 if (mContextView
!= null
) {
1060 mContextView
.setContentHeight(getMeasuredHeight());
1063 if (mProgressView
!= null
&& mProgressView
.getVisibility() != GONE
) {
1064 mProgressView
.measure(MeasureSpec
.makeMeasureSpec(
1065 contentWidth
- mProgressBarPadding
* 2, MeasureSpec
.EXACTLY
),
1066 MeasureSpec
.makeMeasureSpec(getMeasuredHeight(), MeasureSpec
.AT_MOST
));
1071 protected void onLayout(boolean changed
, int l
, int t
, int r
, int b
) {
1072 int x
= getPaddingLeft();
1073 final int y
= getPaddingTop();
1074 final int contentHeight
= b
- t
- getPaddingTop() - getPaddingBottom();
1076 if (contentHeight
<= 0) {
1077 // Nothing to do if we can't see anything.
1081 HomeView homeLayout
= mExpandedActionView
!= null ? mExpandedHomeLayout
: mHomeLayout
;
1082 if (homeLayout
.getVisibility() != GONE
) {
1083 final int leftOffset
= homeLayout
.getLeftOffset();
1084 x
+= positionChild(homeLayout
, x
+ leftOffset
, y
, contentHeight
) + leftOffset
;
1087 if (mExpandedActionView
== null
) {
1088 final boolean showTitle
= mTitleLayout
!= null
&& mTitleLayout
.getVisibility() != GONE
&&
1089 (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0;
1091 x
+= positionChild(mTitleLayout
, x
, y
, contentHeight
);
1094 switch (mNavigationMode
) {
1095 case ActionBar
.NAVIGATION_MODE_STANDARD
:
1097 case ActionBar
.NAVIGATION_MODE_LIST
:
1098 if (mListNavLayout
!= null
) {
1099 if (showTitle
) x
+= mItemPadding
;
1100 x
+= positionChild(mListNavLayout
, x
, y
, contentHeight
) + mItemPadding
;
1103 case ActionBar
.NAVIGATION_MODE_TABS
:
1104 if (mTabScrollView
!= null
) {
1105 if (showTitle
) x
+= mItemPadding
;
1106 x
+= positionChild(mTabScrollView
, x
, y
, contentHeight
) + mItemPadding
;
1112 int menuLeft
= r
- l
- getPaddingRight();
1113 if (mMenuView
!= null
&& mMenuView
.getParent() == this) {
1114 positionChildInverse(mMenuView
, menuLeft
, y
, contentHeight
);
1115 menuLeft
-= mMenuView
.getMeasuredWidth();
1118 if (mIndeterminateProgressView
!= null
&&
1119 mIndeterminateProgressView
.getVisibility() != GONE
) {
1120 positionChildInverse(mIndeterminateProgressView
, menuLeft
, y
, contentHeight
);
1121 menuLeft
-= mIndeterminateProgressView
.getMeasuredWidth();
1124 View customView
= null
;
1125 if (mExpandedActionView
!= null
) {
1126 customView
= mExpandedActionView
;
1127 } else if ((mDisplayOptions
& ActionBar
.DISPLAY_SHOW_CUSTOM
) != 0 &&
1128 mCustomNavView
!= null
) {
1129 customView
= mCustomNavView
;
1131 if (customView
!= null
) {
1132 ViewGroup
.LayoutParams lp
= customView
.getLayoutParams();
1133 final ActionBar
.LayoutParams ablp
= lp
instanceof ActionBar
.LayoutParams ?
1134 (ActionBar
.LayoutParams
) lp
: null
;
1136 final int gravity
= ablp
!= null ? ablp
.gravity
: DEFAULT_CUSTOM_GRAVITY
;
1137 final int navWidth
= customView
.getMeasuredWidth();
1140 int bottomMargin
= 0;
1142 x
+= ablp
.leftMargin
;
1143 menuLeft
-= ablp
.rightMargin
;
1144 topMargin
= ablp
.topMargin
;
1145 bottomMargin
= ablp
.bottomMargin
;
1148 int hgravity
= gravity
& Gravity
.HORIZONTAL_GRAVITY_MASK
;
1149 // See if we actually have room to truly center; if not push against left or right.
1150 if (hgravity
== Gravity
.CENTER_HORIZONTAL
) {
1151 final int centeredLeft
= ((getRight() - getLeft()) - navWidth
) / 2;
1152 if (centeredLeft
< x
) {
1153 hgravity
= Gravity
.LEFT
;
1154 } else if (centeredLeft
+ navWidth
> menuLeft
) {
1155 hgravity
= Gravity
.RIGHT
;
1157 } else if (gravity
== -1) {
1158 hgravity
= Gravity
.LEFT
;
1163 case Gravity
.CENTER_HORIZONTAL
:
1164 xpos
= ((getRight() - getLeft()) - navWidth
) / 2;
1170 xpos
= menuLeft
- navWidth
;
1174 int vgravity
= gravity
& Gravity
.VERTICAL_GRAVITY_MASK
;
1176 if (gravity
== -1) {
1177 vgravity
= Gravity
.CENTER_VERTICAL
;
1182 case Gravity
.CENTER_VERTICAL
:
1183 final int paddedTop
= getPaddingTop();
1184 final int paddedBottom
= getBottom() - getTop() - getPaddingBottom();
1185 ypos
= ((paddedBottom
- paddedTop
) - customView
.getMeasuredHeight()) / 2;
1188 ypos
= getPaddingTop() + topMargin
;
1190 case Gravity
.BOTTOM
:
1191 ypos
= getHeight() - getPaddingBottom() - customView
.getMeasuredHeight()
1195 final int customWidth
= customView
.getMeasuredWidth();
1196 customView
.layout(xpos
, ypos
, xpos
+ customWidth
,
1197 ypos
+ customView
.getMeasuredHeight());
1201 if (mProgressView
!= null
) {
1202 mProgressView
.bringToFront();
1203 final int halfProgressHeight
= mProgressView
.getMeasuredHeight() / 2;
1204 mProgressView
.layout(mProgressBarPadding
, -halfProgressHeight
,
1205 mProgressBarPadding
+ mProgressView
.getMeasuredWidth(), halfProgressHeight
);
1210 public ViewGroup
.LayoutParams
generateLayoutParams(AttributeSet attrs
) {
1211 return new ActionBar
.LayoutParams(getContext(), attrs
);
1215 public ViewGroup
.LayoutParams
generateLayoutParams(ViewGroup
.LayoutParams lp
) {
1217 lp
= generateDefaultLayoutParams();
1223 public Parcelable
onSaveInstanceState() {
1224 Parcelable superState
= super.onSaveInstanceState();
1225 SavedState state
= new SavedState(superState
);
1227 if (mExpandedMenuPresenter
!= null
&& mExpandedMenuPresenter
.mCurrentExpandedItem
!= null
) {
1228 state
.expandedMenuItemId
= mExpandedMenuPresenter
.mCurrentExpandedItem
.getItemId();
1231 state
.isOverflowOpen
= isOverflowMenuShowing();
1237 public void onRestoreInstanceState(Parcelable p
) {
1238 SavedState state
= (SavedState
) p
;
1240 super.onRestoreInstanceState(state
.getSuperState());
1242 if (state
.expandedMenuItemId
!= 0 &&
1243 mExpandedMenuPresenter
!= null
&& mOptionsMenu
!= null
) {
1244 final MenuItem item
= mOptionsMenu
.findItem(state
.expandedMenuItemId
);
1246 item
.expandActionView();
1250 if (state
.isOverflowOpen
) {
1251 postShowOverflowMenu();
1255 static class SavedState
extends BaseSavedState
{
1256 int expandedMenuItemId
;
1257 boolean isOverflowOpen
;
1259 SavedState(Parcelable superState
) {
1263 private SavedState(Parcel
in) {
1265 expandedMenuItemId
= in.readInt();
1266 isOverflowOpen
= in.readInt() != 0;
1270 public void writeToParcel(Parcel out
, int flags
) {
1271 super.writeToParcel(out
, flags
);
1272 out
.writeInt(expandedMenuItemId
);
1273 out
.writeInt(isOverflowOpen ?
1 : 0);
1276 public static final Parcelable
.Creator
<SavedState
> CREATOR
=
1277 new Parcelable
.Creator
<SavedState
>() {
1278 public SavedState
createFromParcel(Parcel
in) {
1279 return new SavedState(in);
1282 public SavedState
[] newArray(int size
) {
1283 return new SavedState
[size
];
1288 public static class HomeView
extends FrameLayout
{
1289 private View mUpView
;
1290 private ImageView mIconView
;
1291 private int mUpWidth
;
1293 public HomeView(Context context
) {
1294 this(context
, null
);
1297 public HomeView(Context context
, AttributeSet attrs
) {
1298 super(context
, attrs
);
1301 public void setUp(boolean isUp
) {
1302 mUpView
.setVisibility(isUp ? VISIBLE
: GONE
);
1305 public void setIcon(Drawable icon
) {
1306 mIconView
.setImageDrawable(icon
);
1310 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event
) {
1311 onPopulateAccessibilityEvent(event
);
1316 public void onPopulateAccessibilityEvent(AccessibilityEvent event
) {
1317 if (Build
.VERSION
.SDK_INT
>= Build
.VERSION_CODES
.ICE_CREAM_SANDWICH
) {
1318 super.onPopulateAccessibilityEvent(event
);
1320 final CharSequence cdesc
= getContentDescription();
1321 if (!TextUtils
.isEmpty(cdesc
)) {
1322 event
.getText().add(cdesc
);
1327 public boolean dispatchHoverEvent(MotionEvent event
) {
1328 // Don't allow children to hover; we want this to be treated as a single component.
1329 return onHoverEvent(event
);
1333 protected void onFinishInflate() {
1334 mUpView
= findViewById(R
.id
.abs__up
);
1335 mIconView
= (ImageView
) findViewById(R
.id
.abs__home
);
1338 public int getLeftOffset() {
1339 return mUpView
.getVisibility() == GONE ? mUpWidth
: 0;
1343 protected void onMeasure(int widthMeasureSpec
, int heightMeasureSpec
) {
1344 measureChildWithMargins(mUpView
, widthMeasureSpec
, 0, heightMeasureSpec
, 0);
1345 final LayoutParams upLp
= (LayoutParams
) mUpView
.getLayoutParams();
1346 mUpWidth
= upLp
.leftMargin
+ mUpView
.getMeasuredWidth() + upLp
.rightMargin
;
1347 int width
= mUpView
.getVisibility() == GONE ?
0 : mUpWidth
;
1348 int height
= upLp
.topMargin
+ mUpView
.getMeasuredHeight() + upLp
.bottomMargin
;
1349 measureChildWithMargins(mIconView
, widthMeasureSpec
, width
, heightMeasureSpec
, 0);
1350 final LayoutParams iconLp
= (LayoutParams
) mIconView
.getLayoutParams();
1351 width
+= iconLp
.leftMargin
+ mIconView
.getMeasuredWidth() + iconLp
.rightMargin
;
1352 height
= Math
.max(height
,
1353 iconLp
.topMargin
+ mIconView
.getMeasuredHeight() + iconLp
.bottomMargin
);
1355 final int widthMode
= MeasureSpec
.getMode(widthMeasureSpec
);
1356 final int heightMode
= MeasureSpec
.getMode(heightMeasureSpec
);
1357 final int widthSize
= MeasureSpec
.getSize(widthMeasureSpec
);
1358 final int heightSize
= MeasureSpec
.getSize(heightMeasureSpec
);
1360 switch (widthMode
) {
1361 case MeasureSpec
.AT_MOST
:
1362 width
= Math
.min(width
, widthSize
);
1364 case MeasureSpec
.EXACTLY
:
1367 case MeasureSpec
.UNSPECIFIED
:
1371 switch (heightMode
) {
1372 case MeasureSpec
.AT_MOST
:
1373 height
= Math
.min(height
, heightSize
);
1375 case MeasureSpec
.EXACTLY
:
1376 height
= heightSize
;
1378 case MeasureSpec
.UNSPECIFIED
:
1382 setMeasuredDimension(width
, height
);
1386 protected void onLayout(boolean changed
, int l
, int t
, int r
, int b
) {
1387 final int vCenter
= (b
- t
) / 2;
1388 //UNUSED int width = r - l;
1390 if (mUpView
.getVisibility() != GONE
) {
1391 final LayoutParams upLp
= (LayoutParams
) mUpView
.getLayoutParams();
1392 final int upHeight
= mUpView
.getMeasuredHeight();
1393 final int upWidth
= mUpView
.getMeasuredWidth();
1394 final int upTop
= vCenter
- upHeight
/ 2;
1395 mUpView
.layout(0, upTop
, upWidth
, upTop
+ upHeight
);
1396 upOffset
= upLp
.leftMargin
+ upWidth
+ upLp
.rightMargin
;
1397 //UNUSED width -= upOffset;
1400 final LayoutParams iconLp
= (LayoutParams
) mIconView
.getLayoutParams();
1401 final int iconHeight
= mIconView
.getMeasuredHeight();
1402 final int iconWidth
= mIconView
.getMeasuredWidth();
1403 final int hCenter
= (r
- l
) / 2;
1404 final int iconLeft
= upOffset
+ Math
.max(iconLp
.leftMargin
, hCenter
- iconWidth
/ 2);
1405 final int iconTop
= Math
.max(iconLp
.topMargin
, vCenter
- iconHeight
/ 2);
1406 mIconView
.layout(iconLeft
, iconTop
, iconLeft
+ iconWidth
, iconTop
+ iconHeight
);
1410 private class ExpandedActionViewMenuPresenter
implements MenuPresenter
{
1412 MenuItemImpl mCurrentExpandedItem
;
1415 public void initForMenu(Context context
, MenuBuilder menu
) {
1416 // Clear the expanded action view when menus change.
1417 if (mMenu
!= null
&& mCurrentExpandedItem
!= null
) {
1418 mMenu
.collapseItemActionView(mCurrentExpandedItem
);
1424 public MenuView
getMenuView(ViewGroup root
) {
1429 public void updateMenuView(boolean cleared
) {
1430 // Make sure the expanded item we have is still there.
1431 if (mCurrentExpandedItem
!= null
) {
1432 boolean found
= false
;
1434 if (mMenu
!= null
) {
1435 final int count
= mMenu
.size();
1436 for (int i
= 0; i
< count
; i
++) {
1437 final MenuItem item
= mMenu
.getItem(i
);
1438 if (item
== mCurrentExpandedItem
) {
1446 // The item we had expanded disappeared. Collapse.
1447 collapseItemActionView(mMenu
, mCurrentExpandedItem
);
1453 public void setCallback(Callback cb
) {
1457 public boolean onSubMenuSelected(SubMenuBuilder subMenu
) {
1462 public void onCloseMenu(MenuBuilder menu
, boolean allMenusAreClosing
) {
1466 public boolean flagActionItems() {
1471 public boolean expandItemActionView(MenuBuilder menu
, MenuItemImpl item
) {
1472 mExpandedActionView
= item
.getActionView();
1473 mExpandedHomeLayout
.setIcon(mIcon
.getConstantState().newDrawable(/* TODO getResources() */));
1474 mCurrentExpandedItem
= item
;
1475 if (mExpandedActionView
.getParent() != ActionBarView
.this) {
1476 addView(mExpandedActionView
);
1478 if (mExpandedHomeLayout
.getParent() != ActionBarView
.this) {
1479 addView(mExpandedHomeLayout
);
1481 mHomeLayout
.setVisibility(GONE
);
1482 if (mTitleLayout
!= null
) mTitleLayout
.setVisibility(GONE
);
1483 if (mTabScrollView
!= null
) mTabScrollView
.setVisibility(GONE
);
1484 if (mSpinner
!= null
) mSpinner
.setVisibility(GONE
);
1485 if (mCustomNavView
!= null
) mCustomNavView
.setVisibility(GONE
);
1487 item
.setActionViewExpanded(true
);
1489 if (mExpandedActionView
instanceof CollapsibleActionView
) {
1490 ((CollapsibleActionView
) mExpandedActionView
).onActionViewExpanded();
1497 public boolean collapseItemActionView(MenuBuilder menu
, MenuItemImpl item
) {
1498 // Do this before detaching the actionview from the hierarchy, in case
1499 // it needs to dismiss the soft keyboard, etc.
1500 if (mExpandedActionView
instanceof CollapsibleActionView
) {
1501 ((CollapsibleActionView
) mExpandedActionView
).onActionViewCollapsed();
1504 removeView(mExpandedActionView
);
1505 removeView(mExpandedHomeLayout
);
1506 mExpandedActionView
= null
;
1507 if ((mDisplayOptions
& ActionBar
.DISPLAY_SHOW_HOME
) != 0) {
1508 mHomeLayout
.setVisibility(VISIBLE
);
1510 if ((mDisplayOptions
& ActionBar
.DISPLAY_SHOW_TITLE
) != 0) {
1511 if (mTitleLayout
== null
) {
1514 mTitleLayout
.setVisibility(VISIBLE
);
1517 if (mTabScrollView
!= null
&& mNavigationMode
== ActionBar
.NAVIGATION_MODE_TABS
) {
1518 mTabScrollView
.setVisibility(VISIBLE
);
1520 if (mSpinner
!= null
&& mNavigationMode
== ActionBar
.NAVIGATION_MODE_LIST
) {
1521 mSpinner
.setVisibility(VISIBLE
);
1523 if (mCustomNavView
!= null
&& (mDisplayOptions
& ActionBar
.DISPLAY_SHOW_CUSTOM
) != 0) {
1524 mCustomNavView
.setVisibility(VISIBLE
);
1526 mExpandedHomeLayout
.setIcon(null
);
1527 mCurrentExpandedItem
= null
;
1529 item
.setActionViewExpanded(false
);
1535 public int getId() {
1540 public Parcelable
onSaveInstanceState() {
1545 public void onRestoreInstanceState(Parcelable state
) {