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