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