4636de17f0a1221e2839c270133362b103a85142
[pub/Android/ownCloud.git] / actionbarsherlock / src / com / actionbarsherlock / internal / widget / ActionBarView.java
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
17 package com.actionbarsherlock.internal.widget;
18
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;
48
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;
65
66 import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
67
68 /**
69 * @hide
70 */
71 public class ActionBarView extends AbsActionBarView {
72 private static final String TAG = "ActionBarView";
73 private static final boolean DEBUG = false;
74
75 /**
76 * Display options applied by default
77 */
78 public static final int DISPLAY_DEFAULT = 0;
79
80 /**
81 * Display options that require re-layout as opposed to a simple invalidate
82 */
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;
89
90 private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL;
91
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;
98
99 private HomeView mHomeLayout;
100 private HomeView mExpandedHomeLayout;
101 private LinearLayout mTitleLayout;
102 private TextView mTitleView;
103 private TextView mSubtitleView;
104 private View mTitleUpView;
105
106 private IcsSpinner mSpinner;
107 private IcsLinearLayout mListNavLayout;
108 private ScrollingTabContainerView mTabScrollView;
109 private View mCustomNavView;
110 private IcsProgressBar mProgressView;
111 private IcsProgressBar mIndeterminateProgressView;
112
113 private int mProgressBarPadding;
114 private int mItemPadding;
115
116 private int mTitleStyleRes;
117 private int mSubtitleStyleRes;
118 private int mProgressStyle;
119 private int mIndeterminateProgressStyle;
120
121 private boolean mUserTitle;
122 private boolean mIncludeTabs;
123 private boolean mIsCollapsable;
124 private boolean mIsCollapsed;
125
126 private MenuBuilder mOptionsMenu;
127
128 private ActionBarContextView mContextView;
129
130 private ActionMenuItem mLogoNavItem;
131
132 private SpinnerAdapter mSpinnerAdapter;
133 private OnNavigationListener mCallback;
134
135 //UNUSED private Runnable mTabSelector;
136
137 private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
138 View mExpandedActionView;
139
140 Window.Callback mWindowCallback;
141
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);
148 }
149 }
150 public void onNothingSelected(IcsAdapterView parent) {
151 // Do nothing
152 }
153 };
154
155 private final OnClickListener mExpandedActionViewUpListener = new OnClickListener() {
156 @Override
157 public void onClick(View v) {
158 final MenuItemImpl item = mExpandedMenuPresenter.mCurrentExpandedItem;
159 if (item != null) {
160 item.collapseActionView();
161 }
162 }
163 };
164
165 private final OnClickListener mUpClickListener = new OnClickListener() {
166 public void onClick(View v) {
167 mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
168 }
169 };
170
171 public ActionBarView(Context context, AttributeSet attrs) {
172 super(context, attrs);
173
174 // Background is always provided by the container.
175 setBackgroundResource(0);
176
177 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionBar,
178 R.attr.actionBarStyle, 0);
179
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);
186
187 mLogo = a.getDrawable(R.styleable.SherlockActionBar_logo);
188 if (mLogo == null) {
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);
194 if (resId != 0) {
195 mLogo = context.getResources().getDrawable(resId);
196 }
197 }
198 } else {
199 if (context instanceof Activity) {
200 try {
201 mLogo = pm.getActivityLogo(((Activity) context).getComponentName());
202 } catch (NameNotFoundException e) {
203 Log.e(TAG, "Activity component name not found!", e);
204 }
205 }
206 if (mLogo == null) {
207 mLogo = appInfo.loadLogo(pm);
208 }
209 }
210 }
211
212 mIcon = a.getDrawable(R.styleable.SherlockActionBar_icon);
213 if (mIcon == null) {
214 if (context instanceof Activity) {
215 try {
216 mIcon = pm.getActivityIcon(((Activity) context).getComponentName());
217 } catch (NameNotFoundException e) {
218 Log.e(TAG, "Activity component name not found!", e);
219 }
220 }
221 if (mIcon == null) {
222 mIcon = appInfo.loadIcon(pm);
223 }
224 }
225
226 final LayoutInflater inflater = LayoutInflater.from(context);
227
228 final int homeResId = a.getResourceId(
229 R.styleable.SherlockActionBar_homeLayout,
230 R.layout.abs__action_bar_home);
231
232 mHomeLayout = (HomeView) inflater.inflate(homeResId, this, false);
233
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));
239
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);
245
246 mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_progressBarPadding, 0);
247 mItemPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_itemPadding, 0);
248
249 setDisplayOptions(a.getInt(R.styleable.SherlockActionBar_displayOptions, DISPLAY_DEFAULT));
250
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);
256 }
257
258 mContentHeight = a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0);
259
260 a.recycle();
261
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);
266 }
267
268 /**
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.
272 *
273 * @param activity Activity instance.
274 * @return Logo resource ID.
275 */
276 private static int loadLogoFromManifest(Activity activity) {
277 int logo = 0;
278 try {
279 final String thisPackage = activity.getClass().getName();
280 if (DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage);
281
282 final String packageName = activity.getApplicationInfo().packageName;
283 final AssetManager am = activity.createPackageContext(packageName, 0).getAssets();
284 final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml");
285
286 int eventType = xml.getEventType();
287 while (eventType != XmlPullParser.END_DOCUMENT) {
288 if (eventType == XmlPullParser.START_TAG) {
289 String name = xml.getName();
290
291 if ("application".equals(name)) {
292 //Check if the <application> has the attribute
293 if (DEBUG) Log.d(TAG, "Got <application>");
294
295 for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
296 if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
297
298 if ("logo".equals(xml.getAttributeName(i))) {
299 logo = xml.getAttributeResourceValue(i, 0);
300 break; //out of for loop
301 }
302 }
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;
309
310 for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
311 if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
312
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
321 }
322 isOurActivity = true;
323 }
324
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();
329 }
330 }
331 if (isOurActivity) {
332 //If we matched our activity but it had no logo don't
333 //do any more processing of the manifest
334 break;
335 }
336 }
337 }
338 eventType = xml.nextToken();
339 }
340 } catch (Exception e) {
341 e.printStackTrace();
342 }
343 if (DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(logo));
344 return logo;
345 }
346
347 /*
348 * Must be public so we can dispatch pre-2.2 via ActionBarImpl.
349 */
350 @Override
351 public void onConfigurationChanged(Configuration newConfig) {
352 super.onConfigurationChanged(newConfig);
353
354 mTitleView = null;
355 mSubtitleView = null;
356 mTitleUpView = null;
357 if (mTitleLayout != null && mTitleLayout.getParent() == this) {
358 removeView(mTitleLayout);
359 }
360 mTitleLayout = null;
361 if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
362 initTitle();
363 }
364
365 if (mTabScrollView != null && mIncludeTabs) {
366 ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
367 if (lp != null) {
368 lp.width = LayoutParams.WRAP_CONTENT;
369 lp.height = LayoutParams.MATCH_PARENT;
370 }
371 mTabScrollView.setAllowCollapse(true);
372 }
373 }
374
375 /**
376 * Set the window callback used to invoke menu items; used for dispatching home button presses.
377 * @param cb Window callback to dispatch to
378 */
379 public void setWindowCallback(Window.Callback cb) {
380 mWindowCallback = cb;
381 }
382
383 @Override
384 public void onDetachedFromWindow() {
385 super.onDetachedFromWindow();
386 //UNUSED removeCallbacks(mTabSelector);
387 if (mActionMenuPresenter != null) {
388 mActionMenuPresenter.hideOverflowMenu();
389 mActionMenuPresenter.hideSubMenus();
390 }
391 }
392
393 @Override
394 public boolean shouldDelayChildPressedState() {
395 return false;
396 }
397
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);
403 }
404
405 public void initIndeterminateProgress() {
406 mIndeterminateProgressView = new IcsProgressBar(mContext, null, 0, mIndeterminateProgressStyle);
407 mIndeterminateProgressView.setId(R.id.abs__progress_circular);
408 addView(mIndeterminateProgressView);
409 }
410
411 @Override
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);
418 }
419 if (splitActionBar) {
420 if (mSplitView != null) {
421 mSplitView.addView(mMenuView);
422 }
423 } else {
424 addView(mMenuView);
425 }
426 }
427 if (mSplitView != null) {
428 mSplitView.setVisibility(splitActionBar ? VISIBLE : GONE);
429 }
430 super.setSplitActionBar(splitActionBar);
431 }
432 }
433
434 public boolean isSplitActionBar() {
435 return mSplitActionBar;
436 }
437
438 public boolean hasEmbeddedTabs() {
439 return mIncludeTabs;
440 }
441
442 public void setEmbeddedTabView(ScrollingTabContainerView tabs) {
443 if (mTabScrollView != null) {
444 removeView(mTabScrollView);
445 }
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);
454 }
455 }
456
457 public void setCallback(OnNavigationListener callback) {
458 mCallback = callback;
459 }
460
461 public void setMenu(Menu menu, MenuPresenter.Callback cb) {
462 if (menu == mOptionsMenu) return;
463
464 if (mOptionsMenu != null) {
465 mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);
466 mOptionsMenu.removeMenuPresenter(mExpandedMenuPresenter);
467 }
468
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);
475 }
476 }
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();
482 }
483
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);
496 }
497 addView(menuView, layoutParams);
498 } else {
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);
513 }
514 menuView.setVisibility(getAnimatedVisibility());
515 mSplitView.addView(menuView, layoutParams);
516 } else {
517 // We'll add this later if we missed it this time.
518 menuView.setLayoutParams(layoutParams);
519 }
520 }
521 mMenuView = menuView;
522 }
523
524 private void configPresenters(MenuBuilder builder) {
525 if (builder != null) {
526 builder.addMenuPresenter(mActionMenuPresenter);
527 builder.addMenuPresenter(mExpandedMenuPresenter);
528 } else {
529 mActionMenuPresenter.initForMenu(mContext, null);
530 mExpandedMenuPresenter.initForMenu(mContext, null);
531 mActionMenuPresenter.updateMenuView(true);
532 mExpandedMenuPresenter.updateMenuView(true);
533 }
534 }
535
536 public boolean hasExpandedActionView() {
537 return mExpandedMenuPresenter != null &&
538 mExpandedMenuPresenter.mCurrentExpandedItem != null;
539 }
540
541 public void collapseActionView() {
542 final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
543 mExpandedMenuPresenter.mCurrentExpandedItem;
544 if (item != null) {
545 item.collapseActionView();
546 }
547 }
548
549 public void setCustomNavigationView(View view) {
550 final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
551 if (mCustomNavView != null && showCustom) {
552 removeView(mCustomNavView);
553 }
554 mCustomNavView = view;
555 if (mCustomNavView != null && showCustom) {
556 addView(mCustomNavView);
557 }
558 }
559
560 public CharSequence getTitle() {
561 return mTitle;
562 }
563
564 /**
565 * Set the action bar title. This will always replace or override window titles.
566 * @param title Title to set
567 *
568 * @see #setWindowTitle(CharSequence)
569 */
570 public void setTitle(CharSequence title) {
571 mUserTitle = true;
572 setTitleImpl(title);
573 }
574
575 /**
576 * Set the window title. A window title will always be replaced or overridden by a user title.
577 * @param title Title to set
578 *
579 * @see #setTitle(CharSequence)
580 */
581 public void setWindowTitle(CharSequence title) {
582 if (!mUserTitle) {
583 setTitleImpl(title);
584 }
585 }
586
587 private void setTitleImpl(CharSequence title) {
588 mTitle = 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);
595 }
596 if (mLogoNavItem != null) {
597 mLogoNavItem.setTitle(title);
598 }
599 }
600
601 public CharSequence getSubtitle() {
602 return mSubtitle;
603 }
604
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);
614 }
615 }
616
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.
621 if (!enable) {
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));
626 } else {
627 mHomeLayout.setContentDescription(mContext.getResources().getText(
628 R.string.abs__action_bar_home_description));
629 }
630 }
631
632 public void setDisplayOptions(int options) {
633 final int flagsChanged = mDisplayOptions == -1 ? -1 : options ^ mDisplayOptions;
634 mDisplayOptions = options;
635
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);
640
641 if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
642 final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
643 mHomeLayout.setUp(setUp);
644
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.)
649 if (setUp) {
650 setHomeButtonEnabled(true);
651 }
652 }
653
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);
657 }
658
659 if ((flagsChanged & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
660 if ((options & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
661 initTitle();
662 } else {
663 removeView(mTitleLayout);
664 }
665 }
666
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);
672 }
673
674 if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
675 if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
676 addView(mCustomNavView);
677 } else {
678 removeView(mCustomNavView);
679 }
680 }
681
682 requestLayout();
683 } else {
684 invalidate();
685 }
686
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));
693 } else {
694 mHomeLayout.setContentDescription(mContext.getResources().getText(
695 R.string.abs__action_bar_home_description));
696 }
697 }
698
699 public void setIcon(Drawable icon) {
700 mIcon = icon;
701 if (icon != null &&
702 ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) {
703 mHomeLayout.setIcon(icon);
704 }
705 }
706
707 public void setIcon(int resId) {
708 setIcon(mContext.getResources().getDrawable(resId));
709 }
710
711 public void setLogo(Drawable logo) {
712 mLogo = logo;
713 if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
714 mHomeLayout.setIcon(logo);
715 }
716 }
717
718 public void setLogo(int resId) {
719 setLogo(mContext.getResources().getDrawable(resId));
720 }
721
722 public void setNavigationMode(int mode) {
723 final int oldMode = mNavigationMode;
724 if (mode != oldMode) {
725 switch (oldMode) {
726 case ActionBar.NAVIGATION_MODE_LIST:
727 if (mListNavLayout != null) {
728 removeView(mListNavLayout);
729 }
730 break;
731 case ActionBar.NAVIGATION_MODE_TABS:
732 if (mTabScrollView != null && mIncludeTabs) {
733 removeView(mTabScrollView);
734 }
735 }
736
737 switch (mode) {
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);
748 }
749 if (mSpinner.getAdapter() != mSpinnerAdapter) {
750 mSpinner.setAdapter(mSpinnerAdapter);
751 }
752 mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
753 addView(mListNavLayout);
754 break;
755 case ActionBar.NAVIGATION_MODE_TABS:
756 if (mTabScrollView != null && mIncludeTabs) {
757 addView(mTabScrollView);
758 }
759 break;
760 }
761 mNavigationMode = mode;
762 requestLayout();
763 }
764 }
765
766 public void setDropdownAdapter(SpinnerAdapter adapter) {
767 mSpinnerAdapter = adapter;
768 if (mSpinner != null) {
769 mSpinner.setAdapter(adapter);
770 }
771 }
772
773 public SpinnerAdapter getDropdownAdapter() {
774 return mSpinnerAdapter;
775 }
776
777 public void setDropdownSelectedPosition(int position) {
778 mSpinner.setSelection(position);
779 }
780
781 public int getDropdownSelectedPosition() {
782 return mSpinner.getSelectedItemPosition();
783 }
784
785 public View getCustomNavigationView() {
786 return mCustomNavView;
787 }
788
789 public int getNavigationMode() {
790 return mNavigationMode;
791 }
792
793 public int getDisplayOptions() {
794 return mDisplayOptions;
795 }
796
797 @Override
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);
802 }
803
804 @Override
805 protected void onFinishInflate() {
806 super.onFinishInflate();
807
808 addView(mHomeLayout);
809
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);
815 }
816 addView(mCustomNavView);
817 }
818 }
819 }
820
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,
825 this, false);
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);
829
830 mTitleLayout.setOnClickListener(mUpClickListener);
831
832 if (mTitleStyleRes != 0) {
833 mTitleView.setTextAppearance(mContext, mTitleStyleRes);
834 }
835 if (mTitle != null) {
836 mTitleView.setText(mTitle);
837 }
838
839 if (mSubtitleStyleRes != 0) {
840 mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
841 }
842 if (mSubtitle != null) {
843 mSubtitleView.setText(mSubtitle);
844 mSubtitleView.setVisibility(VISIBLE);
845 }
846
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);
851 }
852
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);
858 }
859 }
860
861 public void setContextView(ActionBarContextView view) {
862 mContextView = view;
863 }
864
865 public void setCollapsable(boolean collapsable) {
866 mIsCollapsable = collapsable;
867 }
868
869 public boolean isCollapsed() {
870 return mIsCollapsed;
871 }
872
873 @Override
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)) {
882 visibleChildren++;
883 }
884 }
885
886 if (visibleChildren == 0) {
887 // No size for an empty action bar when collapsable.
888 setMeasuredDimension(0, 0);
889 mIsCollapsed = true;
890 return;
891 }
892 }
893 mIsCollapsed = false;
894
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)");
899 }
900
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\"");
905 }
906
907 int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
908
909 int maxHeight = mContentHeight > 0 ?
910 mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
911
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);
917
918 int availableWidth = contentWidth - paddingLeft - paddingRight;
919 int leftOfCenter = availableWidth / 2;
920 int rightOfCenter = leftOfCenter;
921
922 HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
923
924 if (homeLayout.getVisibility() != GONE) {
925 final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams();
926 int homeWidthSpec;
927 if (lp.width < 0) {
928 homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
929 } else {
930 homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
931 }
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);
937 }
938
939 if (mMenuView != null && mMenuView.getParent() == this) {
940 availableWidth = measureChildView(mMenuView, availableWidth,
941 childSpecHeight, 0);
942 rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth());
943 }
944
945 if (mIndeterminateProgressView != null &&
946 mIndeterminateProgressView.getVisibility() != GONE) {
947 availableWidth = measureChildView(mIndeterminateProgressView, availableWidth,
948 childSpecHeight, 0);
949 rightOfCenter = Math.max(0,
950 rightOfCenter - mIndeterminateProgressView.getMeasuredWidth());
951 }
952
953 final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
954 (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
955
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);
969 }
970 break;
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);
982 }
983 break;
984 }
985 }
986
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;
993 }
994
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;
999
1000 int horizontalMargin = 0;
1001 int verticalMargin = 0;
1002 if (ablp != null) {
1003 horizontalMargin = ablp.leftMargin + ablp.rightMargin;
1004 verticalMargin = ablp.topMargin + ablp.bottomMargin;
1005 }
1006
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;
1012 } else {
1013 customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
1014 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
1015 }
1016 final int customNavHeight = Math.max(0,
1017 (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin);
1018
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;
1026
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;
1031 }
1032
1033 customView.measure(
1034 MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
1035 MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
1036 availableWidth -= horizontalMargin + customView.getMeasuredWidth();
1037 }
1038
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());
1043 }
1044
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;
1052 }
1053 }
1054 setMeasuredDimension(contentWidth, measuredHeight);
1055 } else {
1056 setMeasuredDimension(contentWidth, maxHeight);
1057 }
1058
1059 if (mContextView != null) {
1060 mContextView.setContentHeight(getMeasuredHeight());
1061 }
1062
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));
1067 }
1068 }
1069
1070 @Override
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();
1075
1076 if (contentHeight <= 0) {
1077 // Nothing to do if we can't see anything.
1078 return;
1079 }
1080
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;
1085 }
1086
1087 if (mExpandedActionView == null) {
1088 final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
1089 (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
1090 if (showTitle) {
1091 x += positionChild(mTitleLayout, x, y, contentHeight);
1092 }
1093
1094 switch (mNavigationMode) {
1095 case ActionBar.NAVIGATION_MODE_STANDARD:
1096 break;
1097 case ActionBar.NAVIGATION_MODE_LIST:
1098 if (mListNavLayout != null) {
1099 if (showTitle) x += mItemPadding;
1100 x += positionChild(mListNavLayout, x, y, contentHeight) + mItemPadding;
1101 }
1102 break;
1103 case ActionBar.NAVIGATION_MODE_TABS:
1104 if (mTabScrollView != null) {
1105 if (showTitle) x += mItemPadding;
1106 x += positionChild(mTabScrollView, x, y, contentHeight) + mItemPadding;
1107 }
1108 break;
1109 }
1110 }
1111
1112 int menuLeft = r - l - getPaddingRight();
1113 if (mMenuView != null && mMenuView.getParent() == this) {
1114 positionChildInverse(mMenuView, menuLeft, y, contentHeight);
1115 menuLeft -= mMenuView.getMeasuredWidth();
1116 }
1117
1118 if (mIndeterminateProgressView != null &&
1119 mIndeterminateProgressView.getVisibility() != GONE) {
1120 positionChildInverse(mIndeterminateProgressView, menuLeft, y, contentHeight);
1121 menuLeft -= mIndeterminateProgressView.getMeasuredWidth();
1122 }
1123
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;
1130 }
1131 if (customView != null) {
1132 ViewGroup.LayoutParams lp = customView.getLayoutParams();
1133 final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
1134 (ActionBar.LayoutParams) lp : null;
1135
1136 final int gravity = ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY;
1137 final int navWidth = customView.getMeasuredWidth();
1138
1139 int topMargin = 0;
1140 int bottomMargin = 0;
1141 if (ablp != null) {
1142 x += ablp.leftMargin;
1143 menuLeft -= ablp.rightMargin;
1144 topMargin = ablp.topMargin;
1145 bottomMargin = ablp.bottomMargin;
1146 }
1147
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;
1156 }
1157 } else if (gravity == -1) {
1158 hgravity = Gravity.LEFT;
1159 }
1160
1161 int xpos = 0;
1162 switch (hgravity) {
1163 case Gravity.CENTER_HORIZONTAL:
1164 xpos = ((getRight() - getLeft()) - navWidth) / 2;
1165 break;
1166 case Gravity.LEFT:
1167 xpos = x;
1168 break;
1169 case Gravity.RIGHT:
1170 xpos = menuLeft - navWidth;
1171 break;
1172 }
1173
1174 int vgravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
1175
1176 if (gravity == -1) {
1177 vgravity = Gravity.CENTER_VERTICAL;
1178 }
1179
1180 int ypos = 0;
1181 switch (vgravity) {
1182 case Gravity.CENTER_VERTICAL:
1183 final int paddedTop = getPaddingTop();
1184 final int paddedBottom = getBottom() - getTop() - getPaddingBottom();
1185 ypos = ((paddedBottom - paddedTop) - customView.getMeasuredHeight()) / 2;
1186 break;
1187 case Gravity.TOP:
1188 ypos = getPaddingTop() + topMargin;
1189 break;
1190 case Gravity.BOTTOM:
1191 ypos = getHeight() - getPaddingBottom() - customView.getMeasuredHeight()
1192 - bottomMargin;
1193 break;
1194 }
1195 final int customWidth = customView.getMeasuredWidth();
1196 customView.layout(xpos, ypos, xpos + customWidth,
1197 ypos + customView.getMeasuredHeight());
1198 x += customWidth;
1199 }
1200
1201 if (mProgressView != null) {
1202 mProgressView.bringToFront();
1203 final int halfProgressHeight = mProgressView.getMeasuredHeight() / 2;
1204 mProgressView.layout(mProgressBarPadding, -halfProgressHeight,
1205 mProgressBarPadding + mProgressView.getMeasuredWidth(), halfProgressHeight);
1206 }
1207 }
1208
1209 @Override
1210 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
1211 return new ActionBar.LayoutParams(getContext(), attrs);
1212 }
1213
1214 @Override
1215 public ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
1216 if (lp == null) {
1217 lp = generateDefaultLayoutParams();
1218 }
1219 return lp;
1220 }
1221
1222 @Override
1223 public Parcelable onSaveInstanceState() {
1224 Parcelable superState = super.onSaveInstanceState();
1225 SavedState state = new SavedState(superState);
1226
1227 if (mExpandedMenuPresenter != null && mExpandedMenuPresenter.mCurrentExpandedItem != null) {
1228 state.expandedMenuItemId = mExpandedMenuPresenter.mCurrentExpandedItem.getItemId();
1229 }
1230
1231 state.isOverflowOpen = isOverflowMenuShowing();
1232
1233 return state;
1234 }
1235
1236 @Override
1237 public void onRestoreInstanceState(Parcelable p) {
1238 SavedState state = (SavedState) p;
1239
1240 super.onRestoreInstanceState(state.getSuperState());
1241
1242 if (state.expandedMenuItemId != 0 &&
1243 mExpandedMenuPresenter != null && mOptionsMenu != null) {
1244 final MenuItem item = mOptionsMenu.findItem(state.expandedMenuItemId);
1245 if (item != null) {
1246 item.expandActionView();
1247 }
1248 }
1249
1250 if (state.isOverflowOpen) {
1251 postShowOverflowMenu();
1252 }
1253 }
1254
1255 static class SavedState extends BaseSavedState {
1256 int expandedMenuItemId;
1257 boolean isOverflowOpen;
1258
1259 SavedState(Parcelable superState) {
1260 super(superState);
1261 }
1262
1263 private SavedState(Parcel in) {
1264 super(in);
1265 expandedMenuItemId = in.readInt();
1266 isOverflowOpen = in.readInt() != 0;
1267 }
1268
1269 @Override
1270 public void writeToParcel(Parcel out, int flags) {
1271 super.writeToParcel(out, flags);
1272 out.writeInt(expandedMenuItemId);
1273 out.writeInt(isOverflowOpen ? 1 : 0);
1274 }
1275
1276 public static final Parcelable.Creator<SavedState> CREATOR =
1277 new Parcelable.Creator<SavedState>() {
1278 public SavedState createFromParcel(Parcel in) {
1279 return new SavedState(in);
1280 }
1281
1282 public SavedState[] newArray(int size) {
1283 return new SavedState[size];
1284 }
1285 };
1286 }
1287
1288 public static class HomeView extends FrameLayout {
1289 private View mUpView;
1290 private ImageView mIconView;
1291 private int mUpWidth;
1292
1293 public HomeView(Context context) {
1294 this(context, null);
1295 }
1296
1297 public HomeView(Context context, AttributeSet attrs) {
1298 super(context, attrs);
1299 }
1300
1301 public void setUp(boolean isUp) {
1302 mUpView.setVisibility(isUp ? VISIBLE : GONE);
1303 }
1304
1305 public void setIcon(Drawable icon) {
1306 mIconView.setImageDrawable(icon);
1307 }
1308
1309 @Override
1310 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1311 onPopulateAccessibilityEvent(event);
1312 return true;
1313 }
1314
1315 @Override
1316 public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
1317 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
1318 super.onPopulateAccessibilityEvent(event);
1319 }
1320 final CharSequence cdesc = getContentDescription();
1321 if (!TextUtils.isEmpty(cdesc)) {
1322 event.getText().add(cdesc);
1323 }
1324 }
1325
1326 @Override
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);
1330 }
1331
1332 @Override
1333 protected void onFinishInflate() {
1334 mUpView = findViewById(R.id.abs__up);
1335 mIconView = (ImageView) findViewById(R.id.abs__home);
1336 }
1337
1338 public int getLeftOffset() {
1339 return mUpView.getVisibility() == GONE ? mUpWidth : 0;
1340 }
1341
1342 @Override
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);
1354
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);
1359
1360 switch (widthMode) {
1361 case MeasureSpec.AT_MOST:
1362 width = Math.min(width, widthSize);
1363 break;
1364 case MeasureSpec.EXACTLY:
1365 width = widthSize;
1366 break;
1367 case MeasureSpec.UNSPECIFIED:
1368 default:
1369 break;
1370 }
1371 switch (heightMode) {
1372 case MeasureSpec.AT_MOST:
1373 height = Math.min(height, heightSize);
1374 break;
1375 case MeasureSpec.EXACTLY:
1376 height = heightSize;
1377 break;
1378 case MeasureSpec.UNSPECIFIED:
1379 default:
1380 break;
1381 }
1382 setMeasuredDimension(width, height);
1383 }
1384
1385 @Override
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;
1389 int upOffset = 0;
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;
1398 l += upOffset;
1399 }
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);
1407 }
1408 }
1409
1410 private class ExpandedActionViewMenuPresenter implements MenuPresenter {
1411 MenuBuilder mMenu;
1412 MenuItemImpl mCurrentExpandedItem;
1413
1414 @Override
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);
1419 }
1420 mMenu = menu;
1421 }
1422
1423 @Override
1424 public MenuView getMenuView(ViewGroup root) {
1425 return null;
1426 }
1427
1428 @Override
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;
1433
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) {
1439 found = true;
1440 break;
1441 }
1442 }
1443 }
1444
1445 if (!found) {
1446 // The item we had expanded disappeared. Collapse.
1447 collapseItemActionView(mMenu, mCurrentExpandedItem);
1448 }
1449 }
1450 }
1451
1452 @Override
1453 public void setCallback(Callback cb) {
1454 }
1455
1456 @Override
1457 public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
1458 return false;
1459 }
1460
1461 @Override
1462 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
1463 }
1464
1465 @Override
1466 public boolean flagActionItems() {
1467 return false;
1468 }
1469
1470 @Override
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);
1477 }
1478 if (mExpandedHomeLayout.getParent() != ActionBarView.this) {
1479 addView(mExpandedHomeLayout);
1480 }
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);
1486 requestLayout();
1487 item.setActionViewExpanded(true);
1488
1489 if (mExpandedActionView instanceof CollapsibleActionView) {
1490 ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
1491 }
1492
1493 return true;
1494 }
1495
1496 @Override
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();
1502 }
1503
1504 removeView(mExpandedActionView);
1505 removeView(mExpandedHomeLayout);
1506 mExpandedActionView = null;
1507 if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) {
1508 mHomeLayout.setVisibility(VISIBLE);
1509 }
1510 if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
1511 if (mTitleLayout == null) {
1512 initTitle();
1513 } else {
1514 mTitleLayout.setVisibility(VISIBLE);
1515 }
1516 }
1517 if (mTabScrollView != null && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) {
1518 mTabScrollView.setVisibility(VISIBLE);
1519 }
1520 if (mSpinner != null && mNavigationMode == ActionBar.NAVIGATION_MODE_LIST) {
1521 mSpinner.setVisibility(VISIBLE);
1522 }
1523 if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
1524 mCustomNavView.setVisibility(VISIBLE);
1525 }
1526 mExpandedHomeLayout.setIcon(null);
1527 mCurrentExpandedItem = null;
1528 requestLayout();
1529 item.setActionViewExpanded(false);
1530
1531 return true;
1532 }
1533
1534 @Override
1535 public int getId() {
1536 return 0;
1537 }
1538
1539 @Override
1540 public Parcelable onSaveInstanceState() {
1541 return null;
1542 }
1543
1544 @Override
1545 public void onRestoreInstanceState(Parcelable state) {
1546 }
1547 }
1548 }