ActionBarImpl.java revision faa6ffa484f6f2a334c8bf2c7a9dc693a61608f3
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.app; 18 19import com.android.internal.view.menu.MenuBuilder; 20import com.android.internal.view.menu.MenuPopupHelper; 21import com.android.internal.view.menu.SubMenuBuilder; 22import com.android.internal.widget.ActionBarContainer; 23import com.android.internal.widget.ActionBarContextView; 24import com.android.internal.widget.ActionBarView; 25import com.android.internal.widget.ScrollingTabContainerView; 26 27import android.animation.Animator; 28import android.animation.Animator.AnimatorListener; 29import android.animation.AnimatorListenerAdapter; 30import android.animation.AnimatorSet; 31import android.animation.ObjectAnimator; 32import android.app.ActionBar; 33import android.app.Activity; 34import android.app.Dialog; 35import android.app.FragmentTransaction; 36import android.content.Context; 37import android.content.res.Configuration; 38import android.content.res.Resources; 39import android.graphics.drawable.Drawable; 40import android.os.Build; 41import android.os.Handler; 42import android.util.TypedValue; 43import android.view.ActionMode; 44import android.view.ContextThemeWrapper; 45import android.view.LayoutInflater; 46import android.view.Menu; 47import android.view.MenuInflater; 48import android.view.MenuItem; 49import android.view.View; 50import android.view.Window; 51import android.widget.SpinnerAdapter; 52 53import java.lang.ref.WeakReference; 54import java.util.ArrayList; 55 56/** 57 * ActionBarImpl is the ActionBar implementation used 58 * by devices of all screen sizes. If it detects a compatible decor, 59 * it will split contextual modes across both the ActionBarView at 60 * the top of the screen and a horizontal LinearLayout at the bottom 61 * which is normally hidden. 62 */ 63public class ActionBarImpl extends ActionBar { 64 private static final String TAG = "ActionBarImpl"; 65 66 private Context mContext; 67 private Context mThemedContext; 68 private Activity mActivity; 69 private Dialog mDialog; 70 71 private ActionBarContainer mContainerView; 72 private ActionBarView mActionView; 73 private ActionBarContextView mContextView; 74 private ActionBarContainer mSplitView; 75 private View mContentView; 76 private ScrollingTabContainerView mTabScrollView; 77 78 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>(); 79 80 private TabImpl mSelectedTab; 81 private int mSavedTabPosition = INVALID_POSITION; 82 83 ActionModeImpl mActionMode; 84 ActionMode mDeferredDestroyActionMode; 85 ActionMode.Callback mDeferredModeDestroyCallback; 86 87 private boolean mLastMenuVisibility; 88 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = 89 new ArrayList<OnMenuVisibilityListener>(); 90 91 private static final int CONTEXT_DISPLAY_NORMAL = 0; 92 private static final int CONTEXT_DISPLAY_SPLIT = 1; 93 94 private static final int INVALID_POSITION = -1; 95 96 private int mContextDisplayMode; 97 private boolean mHasEmbeddedTabs; 98 99 final Handler mHandler = new Handler(); 100 Runnable mTabSelector; 101 102 private Animator mCurrentShowAnim; 103 private Animator mCurrentModeAnim; 104 private boolean mShowHideAnimationEnabled; 105 boolean mWasHiddenBeforeMode; 106 107 final AnimatorListener mHideListener = new AnimatorListenerAdapter() { 108 @Override 109 public void onAnimationEnd(Animator animation) { 110 if (mContentView != null) { 111 mContentView.setTranslationY(0); 112 mContainerView.setTranslationY(0); 113 } 114 mContainerView.setVisibility(View.GONE); 115 mContainerView.setTransitioning(false); 116 mCurrentShowAnim = null; 117 completeDeferredDestroyActionMode(); 118 } 119 }; 120 121 final AnimatorListener mShowListener = new AnimatorListenerAdapter() { 122 @Override 123 public void onAnimationEnd(Animator animation) { 124 mCurrentShowAnim = null; 125 mContainerView.requestLayout(); 126 } 127 }; 128 129 public ActionBarImpl(Activity activity) { 130 mActivity = activity; 131 Window window = activity.getWindow(); 132 View decor = window.getDecorView(); 133 init(decor); 134 if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) { 135 mContentView = decor.findViewById(android.R.id.content); 136 } 137 } 138 139 public ActionBarImpl(Dialog dialog) { 140 mDialog = dialog; 141 init(dialog.getWindow().getDecorView()); 142 } 143 144 private void init(View decor) { 145 mContext = decor.getContext(); 146 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar); 147 mContextView = (ActionBarContextView) decor.findViewById( 148 com.android.internal.R.id.action_context_bar); 149 mContainerView = (ActionBarContainer) decor.findViewById( 150 com.android.internal.R.id.action_bar_container); 151 mSplitView = (ActionBarContainer) decor.findViewById( 152 com.android.internal.R.id.split_action_bar); 153 154 if (mActionView == null || mContextView == null || mContainerView == null) { 155 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 156 "with a compatible window decor layout"); 157 } 158 159 mHasEmbeddedTabs = mContext.getResources().getBoolean( 160 com.android.internal.R.bool.action_bar_embed_tabs); 161 mActionView.setContextView(mContextView); 162 mContextDisplayMode = mActionView.isSplitActionBar() ? 163 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; 164 165 // Older apps get the home button interaction enabled by default. 166 // Newer apps need to enable it explicitly. 167 setHomeButtonEnabled(mContext.getApplicationInfo().targetSdkVersion < 168 Build.VERSION_CODES.ICE_CREAM_SANDWICH); 169 } 170 171 public void onConfigurationChanged(Configuration newConfig) { 172 mHasEmbeddedTabs = mContext.getResources().getBoolean( 173 com.android.internal.R.bool.action_bar_embed_tabs); 174 175 // Switch tab layout configuration if needed 176 if (!mHasEmbeddedTabs) { 177 mActionView.setEmbeddedTabView(null); 178 mContainerView.setTabContainer(mTabScrollView); 179 } else { 180 mContainerView.setTabContainer(null); 181 if (mTabScrollView != null) { 182 mTabScrollView.setVisibility(View.VISIBLE); 183 } 184 mActionView.setEmbeddedTabView(mTabScrollView); 185 } 186 mActionView.setCollapsable(!mHasEmbeddedTabs && 187 getNavigationMode() == NAVIGATION_MODE_TABS); 188 } 189 190 private void ensureTabsExist() { 191 if (mTabScrollView != null) { 192 return; 193 } 194 195 ScrollingTabContainerView tabScroller = mActionView.createTabContainer(); 196 197 if (mHasEmbeddedTabs) { 198 tabScroller.setVisibility(View.VISIBLE); 199 mActionView.setEmbeddedTabView(tabScroller); 200 } else { 201 tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ? 202 View.VISIBLE : View.GONE); 203 mContainerView.setTabContainer(tabScroller); 204 } 205 mTabScrollView = tabScroller; 206 } 207 208 void completeDeferredDestroyActionMode() { 209 if (mDeferredModeDestroyCallback != null) { 210 mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode); 211 mDeferredDestroyActionMode = null; 212 mDeferredModeDestroyCallback = null; 213 } 214 } 215 216 /** 217 * Enables or disables animation between show/hide states. 218 * If animation is disabled using this method, animations in progress 219 * will be finished. 220 * 221 * @param enabled true to animate, false to not animate. 222 */ 223 public void setShowHideAnimationEnabled(boolean enabled) { 224 mShowHideAnimationEnabled = enabled; 225 if (!enabled && mCurrentShowAnim != null) { 226 mCurrentShowAnim.end(); 227 } 228 } 229 230 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 231 mMenuVisibilityListeners.add(listener); 232 } 233 234 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 235 mMenuVisibilityListeners.remove(listener); 236 } 237 238 public void dispatchMenuVisibilityChanged(boolean isVisible) { 239 if (isVisible == mLastMenuVisibility) { 240 return; 241 } 242 mLastMenuVisibility = isVisible; 243 244 final int count = mMenuVisibilityListeners.size(); 245 for (int i = 0; i < count; i++) { 246 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible); 247 } 248 } 249 250 @Override 251 public void setCustomView(int resId) { 252 setCustomView(LayoutInflater.from(mContext).inflate(resId, mActionView, false)); 253 } 254 255 @Override 256 public void setDisplayUseLogoEnabled(boolean useLogo) { 257 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO); 258 } 259 260 @Override 261 public void setDisplayShowHomeEnabled(boolean showHome) { 262 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME); 263 } 264 265 @Override 266 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { 267 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP); 268 } 269 270 @Override 271 public void setDisplayShowTitleEnabled(boolean showTitle) { 272 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE); 273 } 274 275 @Override 276 public void setDisplayShowCustomEnabled(boolean showCustom) { 277 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM); 278 } 279 280 @Override 281 public void setHomeButtonEnabled(boolean enable) { 282 mActionView.setHomeButtonEnabled(enable); 283 } 284 285 @Override 286 public void setTitle(int resId) { 287 setTitle(mContext.getString(resId)); 288 } 289 290 @Override 291 public void setSubtitle(int resId) { 292 setSubtitle(mContext.getString(resId)); 293 } 294 295 public void setSelectedNavigationItem(int position) { 296 switch (mActionView.getNavigationMode()) { 297 case NAVIGATION_MODE_TABS: 298 selectTab(mTabs.get(position)); 299 break; 300 case NAVIGATION_MODE_LIST: 301 mActionView.setDropdownSelectedPosition(position); 302 break; 303 default: 304 throw new IllegalStateException( 305 "setSelectedNavigationIndex not valid for current navigation mode"); 306 } 307 } 308 309 public void removeAllTabs() { 310 cleanupTabs(); 311 } 312 313 private void cleanupTabs() { 314 if (mSelectedTab != null) { 315 selectTab(null); 316 } 317 mTabs.clear(); 318 if (mTabScrollView != null) { 319 mTabScrollView.removeAllTabs(); 320 } 321 mSavedTabPosition = INVALID_POSITION; 322 } 323 324 public void setTitle(CharSequence title) { 325 mActionView.setTitle(title); 326 } 327 328 public void setSubtitle(CharSequence subtitle) { 329 mActionView.setSubtitle(subtitle); 330 } 331 332 public void setDisplayOptions(int options) { 333 mActionView.setDisplayOptions(options); 334 } 335 336 public void setDisplayOptions(int options, int mask) { 337 final int current = mActionView.getDisplayOptions(); 338 mActionView.setDisplayOptions((options & mask) | (current & ~mask)); 339 } 340 341 public void setBackgroundDrawable(Drawable d) { 342 mContainerView.setBackgroundDrawable(d); 343 } 344 345 public View getCustomView() { 346 return mActionView.getCustomNavigationView(); 347 } 348 349 public CharSequence getTitle() { 350 return mActionView.getTitle(); 351 } 352 353 public CharSequence getSubtitle() { 354 return mActionView.getSubtitle(); 355 } 356 357 public int getNavigationMode() { 358 return mActionView.getNavigationMode(); 359 } 360 361 public int getDisplayOptions() { 362 return mActionView.getDisplayOptions(); 363 } 364 365 public ActionMode startActionMode(ActionMode.Callback callback) { 366 boolean wasHidden = false; 367 if (mActionMode != null) { 368 wasHidden = mWasHiddenBeforeMode; 369 mActionMode.finish(); 370 } 371 372 mContextView.killMode(); 373 ActionModeImpl mode = new ActionModeImpl(callback); 374 if (mode.dispatchOnCreate()) { 375 mWasHiddenBeforeMode = !isShowing() || wasHidden; 376 mode.invalidate(); 377 mContextView.initForMode(mode); 378 animateToMode(true); 379 if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { 380 // TODO animate this 381 mSplitView.setVisibility(View.VISIBLE); 382 } 383 mActionMode = mode; 384 return mode; 385 } 386 return null; 387 } 388 389 private void configureTab(Tab tab, int position) { 390 final TabImpl tabi = (TabImpl) tab; 391 final ActionBar.TabListener callback = tabi.getCallback(); 392 393 if (callback == null) { 394 throw new IllegalStateException("Action Bar Tab must have a Callback"); 395 } 396 397 tabi.setPosition(position); 398 mTabs.add(position, tabi); 399 400 final int count = mTabs.size(); 401 for (int i = position + 1; i < count; i++) { 402 mTabs.get(i).setPosition(i); 403 } 404 } 405 406 @Override 407 public void addTab(Tab tab) { 408 addTab(tab, mTabs.isEmpty()); 409 } 410 411 @Override 412 public void addTab(Tab tab, int position) { 413 addTab(tab, position, mTabs.isEmpty()); 414 } 415 416 @Override 417 public void addTab(Tab tab, boolean setSelected) { 418 ensureTabsExist(); 419 mTabScrollView.addTab(tab, setSelected); 420 configureTab(tab, mTabs.size()); 421 if (setSelected) { 422 selectTab(tab); 423 } 424 } 425 426 @Override 427 public void addTab(Tab tab, int position, boolean setSelected) { 428 ensureTabsExist(); 429 mTabScrollView.addTab(tab, position, setSelected); 430 configureTab(tab, position); 431 if (setSelected) { 432 selectTab(tab); 433 } 434 } 435 436 @Override 437 public Tab newTab() { 438 return new TabImpl(); 439 } 440 441 @Override 442 public void removeTab(Tab tab) { 443 removeTabAt(tab.getPosition()); 444 } 445 446 @Override 447 public void removeTabAt(int position) { 448 if (mTabScrollView == null) { 449 // No tabs around to remove 450 return; 451 } 452 453 int selectedTabPosition = mSelectedTab != null 454 ? mSelectedTab.getPosition() : mSavedTabPosition; 455 mTabScrollView.removeTabAt(position); 456 TabImpl removedTab = mTabs.remove(position); 457 if (removedTab != null) { 458 removedTab.setPosition(-1); 459 } 460 461 final int newTabCount = mTabs.size(); 462 for (int i = position; i < newTabCount; i++) { 463 mTabs.get(i).setPosition(i); 464 } 465 466 if (selectedTabPosition == position) { 467 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); 468 } 469 } 470 471 @Override 472 public void selectTab(Tab tab) { 473 if (getNavigationMode() != NAVIGATION_MODE_TABS) { 474 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION; 475 return; 476 } 477 478 final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction() 479 .disallowAddToBackStack(); 480 481 if (mSelectedTab == tab) { 482 if (mSelectedTab != null) { 483 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans); 484 mTabScrollView.animateToTab(tab.getPosition()); 485 } 486 } else { 487 mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION); 488 if (mSelectedTab != null) { 489 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans); 490 } 491 mSelectedTab = (TabImpl) tab; 492 if (mSelectedTab != null) { 493 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans); 494 } 495 } 496 497 if (!trans.isEmpty()) { 498 trans.commit(); 499 } 500 } 501 502 @Override 503 public Tab getSelectedTab() { 504 return mSelectedTab; 505 } 506 507 @Override 508 public int getHeight() { 509 return mContainerView.getHeight(); 510 } 511 512 @Override 513 public void show() { 514 show(true); 515 } 516 517 void show(boolean markHiddenBeforeMode) { 518 if (mCurrentShowAnim != null) { 519 mCurrentShowAnim.end(); 520 } 521 if (mContainerView.getVisibility() == View.VISIBLE) { 522 if (markHiddenBeforeMode) mWasHiddenBeforeMode = false; 523 return; 524 } 525 mContainerView.setVisibility(View.VISIBLE); 526 527 if (mShowHideAnimationEnabled) { 528 mContainerView.setAlpha(0); 529 AnimatorSet anim = new AnimatorSet(); 530 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1)); 531 if (mContentView != null) { 532 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", 533 -mContainerView.getHeight(), 0)); 534 mContainerView.setTranslationY(-mContainerView.getHeight()); 535 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0)); 536 } 537 if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { 538 mSplitView.setAlpha(0); 539 b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1)); 540 } 541 anim.addListener(mShowListener); 542 mCurrentShowAnim = anim; 543 anim.start(); 544 } else { 545 mContainerView.setAlpha(1); 546 mContainerView.setTranslationY(0); 547 mShowListener.onAnimationEnd(null); 548 } 549 } 550 551 @Override 552 public void hide() { 553 if (mCurrentShowAnim != null) { 554 mCurrentShowAnim.end(); 555 } 556 if (mContainerView.getVisibility() == View.GONE) { 557 return; 558 } 559 560 if (mShowHideAnimationEnabled) { 561 mContainerView.setAlpha(1); 562 mContainerView.setTransitioning(true); 563 AnimatorSet anim = new AnimatorSet(); 564 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0)); 565 if (mContentView != null) { 566 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", 567 0, -mContainerView.getHeight())); 568 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 569 -mContainerView.getHeight())); 570 } 571 if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) { 572 mSplitView.setAlpha(1); 573 b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0)); 574 } 575 anim.addListener(mHideListener); 576 mCurrentShowAnim = anim; 577 anim.start(); 578 } else { 579 mHideListener.onAnimationEnd(null); 580 } 581 } 582 583 public boolean isShowing() { 584 return mContainerView.getVisibility() == View.VISIBLE; 585 } 586 587 void animateToMode(boolean toActionMode) { 588 if (toActionMode) { 589 show(false); 590 } 591 if (mCurrentModeAnim != null) { 592 mCurrentModeAnim.end(); 593 } 594 595 mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE); 596 mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE); 597 if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) { 598 mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE); 599 } 600 } 601 602 public Context getThemedContext() { 603 if (mThemedContext == null) { 604 TypedValue outValue = new TypedValue(); 605 Resources.Theme currentTheme = mContext.getTheme(); 606 currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme, 607 outValue, true); 608 final int targetThemeRes = outValue.resourceId; 609 610 if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) { 611 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes); 612 } else { 613 mThemedContext = mContext; 614 } 615 } 616 return mThemedContext; 617 } 618 619 /** 620 * @hide 621 */ 622 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback { 623 private ActionMode.Callback mCallback; 624 private MenuBuilder mMenu; 625 private WeakReference<View> mCustomView; 626 627 public ActionModeImpl(ActionMode.Callback callback) { 628 mCallback = callback; 629 mMenu = new MenuBuilder(mActionView.getContext()) 630 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 631 mMenu.setCallback(this); 632 } 633 634 @Override 635 public MenuInflater getMenuInflater() { 636 return new MenuInflater(mContext); 637 } 638 639 @Override 640 public Menu getMenu() { 641 return mMenu; 642 } 643 644 @Override 645 public void finish() { 646 if (mActionMode != this) { 647 // Not the active action mode - no-op 648 return; 649 } 650 651 // If we were hidden before the mode was shown, defer the onDestroy 652 // callback until the animation is finished and associated relayout 653 // is about to happen. This lets apps better anticipate visibility 654 // and layout behavior. 655 if (mWasHiddenBeforeMode) { 656 mDeferredDestroyActionMode = this; 657 mDeferredModeDestroyCallback = mCallback; 658 } else { 659 mCallback.onDestroyActionMode(this); 660 } 661 mCallback = null; 662 animateToMode(false); 663 664 // Clear out the context mode views after the animation finishes 665 mContextView.closeMode(); 666 667 mActionMode = null; 668 669 if (mWasHiddenBeforeMode) { 670 hide(); 671 } 672 } 673 674 @Override 675 public void invalidate() { 676 mMenu.stopDispatchingItemsChanged(); 677 try { 678 mCallback.onPrepareActionMode(this, mMenu); 679 } finally { 680 mMenu.startDispatchingItemsChanged(); 681 } 682 } 683 684 public boolean dispatchOnCreate() { 685 mMenu.stopDispatchingItemsChanged(); 686 try { 687 return mCallback.onCreateActionMode(this, mMenu); 688 } finally { 689 mMenu.startDispatchingItemsChanged(); 690 } 691 } 692 693 @Override 694 public void setCustomView(View view) { 695 mContextView.setCustomView(view); 696 mCustomView = new WeakReference<View>(view); 697 } 698 699 @Override 700 public void setSubtitle(CharSequence subtitle) { 701 mContextView.setSubtitle(subtitle); 702 } 703 704 @Override 705 public void setTitle(CharSequence title) { 706 mContextView.setTitle(title); 707 } 708 709 @Override 710 public void setTitle(int resId) { 711 setTitle(mContext.getResources().getString(resId)); 712 } 713 714 @Override 715 public void setSubtitle(int resId) { 716 setSubtitle(mContext.getResources().getString(resId)); 717 } 718 719 @Override 720 public CharSequence getTitle() { 721 return mContextView.getTitle(); 722 } 723 724 @Override 725 public CharSequence getSubtitle() { 726 return mContextView.getSubtitle(); 727 } 728 729 @Override 730 public View getCustomView() { 731 return mCustomView != null ? mCustomView.get() : null; 732 } 733 734 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 735 if (mCallback != null) { 736 return mCallback.onActionItemClicked(this, item); 737 } else { 738 return false; 739 } 740 } 741 742 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 743 } 744 745 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 746 if (mCallback == null) { 747 return false; 748 } 749 750 if (!subMenu.hasVisibleItems()) { 751 return true; 752 } 753 754 new MenuPopupHelper(mContext, subMenu).show(); 755 return true; 756 } 757 758 public void onCloseSubMenu(SubMenuBuilder menu) { 759 } 760 761 public void onMenuModeChange(MenuBuilder menu) { 762 if (mCallback == null) { 763 return; 764 } 765 invalidate(); 766 mContextView.showOverflowMenu(); 767 } 768 } 769 770 /** 771 * @hide 772 */ 773 public class TabImpl extends ActionBar.Tab { 774 private ActionBar.TabListener mCallback; 775 private Object mTag; 776 private Drawable mIcon; 777 private CharSequence mText; 778 private int mPosition = -1; 779 private View mCustomView; 780 781 @Override 782 public Object getTag() { 783 return mTag; 784 } 785 786 @Override 787 public Tab setTag(Object tag) { 788 mTag = tag; 789 return this; 790 } 791 792 public ActionBar.TabListener getCallback() { 793 return mCallback; 794 } 795 796 @Override 797 public Tab setTabListener(ActionBar.TabListener callback) { 798 mCallback = callback; 799 return this; 800 } 801 802 @Override 803 public View getCustomView() { 804 return mCustomView; 805 } 806 807 @Override 808 public Tab setCustomView(View view) { 809 mCustomView = view; 810 if (mPosition >= 0) { 811 mTabScrollView.updateTab(mPosition); 812 } 813 return this; 814 } 815 816 @Override 817 public Tab setCustomView(int layoutResId) { 818 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null)); 819 } 820 821 @Override 822 public Drawable getIcon() { 823 return mIcon; 824 } 825 826 @Override 827 public int getPosition() { 828 return mPosition; 829 } 830 831 public void setPosition(int position) { 832 mPosition = position; 833 } 834 835 @Override 836 public CharSequence getText() { 837 return mText; 838 } 839 840 @Override 841 public Tab setIcon(Drawable icon) { 842 mIcon = icon; 843 if (mPosition >= 0) { 844 mTabScrollView.updateTab(mPosition); 845 } 846 return this; 847 } 848 849 @Override 850 public Tab setIcon(int resId) { 851 return setIcon(mContext.getResources().getDrawable(resId)); 852 } 853 854 @Override 855 public Tab setText(CharSequence text) { 856 mText = text; 857 if (mPosition >= 0) { 858 mTabScrollView.updateTab(mPosition); 859 } 860 return this; 861 } 862 863 @Override 864 public Tab setText(int resId) { 865 return setText(mContext.getResources().getText(resId)); 866 } 867 868 @Override 869 public void select() { 870 selectTab(this); 871 } 872 } 873 874 @Override 875 public void setCustomView(View view) { 876 mActionView.setCustomNavigationView(view); 877 } 878 879 @Override 880 public void setCustomView(View view, LayoutParams layoutParams) { 881 view.setLayoutParams(layoutParams); 882 mActionView.setCustomNavigationView(view); 883 } 884 885 @Override 886 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) { 887 mActionView.setDropdownAdapter(adapter); 888 mActionView.setCallback(callback); 889 } 890 891 @Override 892 public int getSelectedNavigationIndex() { 893 switch (mActionView.getNavigationMode()) { 894 case NAVIGATION_MODE_TABS: 895 return mSelectedTab != null ? mSelectedTab.getPosition() : -1; 896 case NAVIGATION_MODE_LIST: 897 return mActionView.getDropdownSelectedPosition(); 898 default: 899 return -1; 900 } 901 } 902 903 @Override 904 public int getNavigationItemCount() { 905 switch (mActionView.getNavigationMode()) { 906 case NAVIGATION_MODE_TABS: 907 return mTabs.size(); 908 case NAVIGATION_MODE_LIST: 909 SpinnerAdapter adapter = mActionView.getDropdownAdapter(); 910 return adapter != null ? adapter.getCount() : 0; 911 default: 912 return 0; 913 } 914 } 915 916 @Override 917 public int getTabCount() { 918 return mTabs.size(); 919 } 920 921 @Override 922 public void setNavigationMode(int mode) { 923 final int oldMode = mActionView.getNavigationMode(); 924 switch (oldMode) { 925 case NAVIGATION_MODE_TABS: 926 mSavedTabPosition = getSelectedNavigationIndex(); 927 selectTab(null); 928 if (!mActionView.hasEmbeddedTabs()) { 929 mTabScrollView.setVisibility(View.GONE); 930 } 931 break; 932 } 933 mActionView.setNavigationMode(mode); 934 switch (mode) { 935 case NAVIGATION_MODE_TABS: 936 ensureTabsExist(); 937 if (!mActionView.hasEmbeddedTabs()) { 938 mTabScrollView.setVisibility(View.VISIBLE); 939 } 940 if (mSavedTabPosition != INVALID_POSITION) { 941 setSelectedNavigationItem(mSavedTabPosition); 942 mSavedTabPosition = INVALID_POSITION; 943 } 944 break; 945 } 946 mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs); 947 } 948 949 @Override 950 public Tab getTabAt(int index) { 951 return mTabs.get(index); 952 } 953 954 955 @Override 956 public void setIcon(int resId) { 957 mActionView.setIcon(resId); 958 } 959 960 @Override 961 public void setIcon(Drawable icon) { 962 mActionView.setIcon(icon); 963 } 964 965 @Override 966 public void setLogo(int resId) { 967 mActionView.setLogo(resId); 968 } 969 970 @Override 971 public void setLogo(Drawable logo) { 972 mActionView.setLogo(logo); 973 } 974} 975