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