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