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