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