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