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