ActionBarImpl.java revision d76cee2b09866c5a22c1de45becc03677be52e95
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.ActionBarContextView; 23import com.android.internal.widget.ActionBarView; 24 25import android.animation.Animator; 26import android.animation.Animator.AnimatorListener; 27import android.animation.AnimatorSet; 28import android.animation.ObjectAnimator; 29import android.animation.TimeInterpolator; 30import android.app.ActionBar; 31import android.app.Activity; 32import android.app.Dialog; 33import android.app.Fragment; 34import android.app.FragmentTransaction; 35import android.content.Context; 36import android.graphics.drawable.Drawable; 37import android.os.Handler; 38import android.view.ActionMode; 39import android.view.LayoutInflater; 40import android.view.Menu; 41import android.view.MenuInflater; 42import android.view.MenuItem; 43import android.view.View; 44import android.view.Window; 45import android.view.animation.DecelerateInterpolator; 46import android.widget.FrameLayout; 47import android.widget.LinearLayout; 48import android.widget.SpinnerAdapter; 49 50import java.lang.ref.WeakReference; 51import java.util.ArrayList; 52 53/** 54 * ActionBarImpl is the ActionBar implementation used 55 * by devices of all screen sizes. If it detects a compatible decor, 56 * it will split contextual modes across both the ActionBarView at 57 * the top of the screen and a horizontal LinearLayout at the bottom 58 * which is normally hidden. 59 */ 60public class ActionBarImpl extends ActionBar { 61 private static final int NORMAL_VIEW = 0; 62 private static final int CONTEXT_VIEW = 1; 63 64 private Context mContext; 65 private Activity mActivity; 66 private Dialog mDialog; 67 68 private FrameLayout mContainerView; 69 private ActionBarView mActionView; 70 private ActionBarContextView mUpperContextView; 71 private LinearLayout mLowerContextView; 72 private View mContentView; 73 74 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>(); 75 76 private TabImpl mSelectedTab; 77 private int mSavedTabPosition = INVALID_POSITION; 78 79 private ActionMode mActionMode; 80 81 private boolean mLastMenuVisibility; 82 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = 83 new ArrayList<OnMenuVisibilityListener>(); 84 85 private static final int CONTEXT_DISPLAY_NORMAL = 0; 86 private static final int CONTEXT_DISPLAY_SPLIT = 1; 87 88 private static final int INVALID_POSITION = -1; 89 90 private int mContextDisplayMode; 91 92 final Handler mHandler = new Handler(); 93 94 private Animator mCurrentAnim; 95 96 private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator(); 97 98 final AnimatorListener[] mAfterAnimation = new AnimatorListener[] { 99 new AnimatorListener() { // NORMAL_VIEW 100 @Override 101 public void onAnimationStart(Animator animation) { 102 } 103 104 @Override 105 public void onAnimationEnd(Animator animation) { 106 if (mLowerContextView != null) { 107 mLowerContextView.removeAllViews(); 108 } 109 mCurrentAnim = null; 110 hideAllExcept(NORMAL_VIEW); 111 } 112 113 @Override 114 public void onAnimationCancel(Animator animation) { 115 } 116 117 @Override 118 public void onAnimationRepeat(Animator animation) { 119 } 120 }, 121 new AnimatorListener() { // CONTEXT_VIEW 122 @Override 123 public void onAnimationStart(Animator animation) { 124 } 125 126 @Override 127 public void onAnimationEnd(Animator animation) { 128 mCurrentAnim = null; 129 hideAllExcept(CONTEXT_VIEW); 130 } 131 132 @Override 133 public void onAnimationCancel(Animator animation) { 134 } 135 136 @Override 137 public void onAnimationRepeat(Animator animation) { 138 } 139 } 140 }; 141 142 final AnimatorListener mHideListener = new AnimatorListener() { 143 @Override 144 public void onAnimationStart(Animator animation) { 145 } 146 147 @Override 148 public void onAnimationEnd(Animator animation) { 149 if (mContentView != null) { 150 mContentView.setTranslationY(0); 151 } 152 mContainerView.setVisibility(View.GONE); 153 mCurrentAnim = null; 154 } 155 156 @Override 157 public void onAnimationCancel(Animator animation) { 158 } 159 160 @Override 161 public void onAnimationRepeat(Animator animation) { 162 } 163 }; 164 165 final AnimatorListener mShowListener = new AnimatorListener() { 166 @Override 167 public void onAnimationStart(Animator animation) { 168 } 169 170 @Override 171 public void onAnimationEnd(Animator animation) { 172 mCurrentAnim = null; 173 mContainerView.requestLayout(); 174 } 175 176 @Override 177 public void onAnimationCancel(Animator animation) { 178 } 179 180 @Override 181 public void onAnimationRepeat(Animator animation) { 182 } 183 }; 184 185 public ActionBarImpl(Activity activity) { 186 mActivity = activity; 187 Window window = activity.getWindow(); 188 View decor = window.getDecorView(); 189 init(decor); 190 if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) { 191 mContentView = decor.findViewById(android.R.id.content); 192 } 193 } 194 195 public ActionBarImpl(Dialog dialog) { 196 mDialog = dialog; 197 init(dialog.getWindow().getDecorView()); 198 } 199 200 private void init(View decor) { 201 mContext = decor.getContext(); 202 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar); 203 mUpperContextView = (ActionBarContextView) decor.findViewById( 204 com.android.internal.R.id.action_context_bar); 205 mLowerContextView = (LinearLayout) decor.findViewById( 206 com.android.internal.R.id.lower_action_context_bar); 207 mContainerView = (FrameLayout) decor.findViewById( 208 com.android.internal.R.id.action_bar_container); 209 210 if (mActionView == null || mUpperContextView == null || mContainerView == null) { 211 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 212 "with a compatible window decor layout"); 213 } 214 215 mActionView.setContextView(mUpperContextView); 216 mContextDisplayMode = mLowerContextView == null ? 217 CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT; 218 } 219 220 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 221 mMenuVisibilityListeners.add(listener); 222 } 223 224 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 225 mMenuVisibilityListeners.remove(listener); 226 } 227 228 public void dispatchMenuVisibilityChanged(boolean isVisible) { 229 if (isVisible == mLastMenuVisibility) { 230 return; 231 } 232 mLastMenuVisibility = isVisible; 233 234 final int count = mMenuVisibilityListeners.size(); 235 for (int i = 0; i < count; i++) { 236 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible); 237 } 238 } 239 240 @Override 241 public void setCustomView(int resId) { 242 setCustomView(LayoutInflater.from(mContext).inflate(resId, mActionView, false)); 243 } 244 245 @Override 246 public void setDisplayUseLogoEnabled(boolean useLogo) { 247 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO); 248 } 249 250 @Override 251 public void setDisplayShowHomeEnabled(boolean showHome) { 252 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME); 253 } 254 255 @Override 256 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { 257 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP); 258 } 259 260 @Override 261 public void setDisplayShowTitleEnabled(boolean showTitle) { 262 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE); 263 } 264 265 @Override 266 public void setDisplayShowCustomEnabled(boolean showCustom) { 267 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM); 268 } 269 270 @Override 271 public void setTitle(int resId) { 272 setTitle(mContext.getString(resId)); 273 } 274 275 @Override 276 public void setSubtitle(int resId) { 277 setSubtitle(mContext.getString(resId)); 278 } 279 280 public void setSelectedNavigationItem(int position) { 281 switch (mActionView.getNavigationMode()) { 282 case NAVIGATION_MODE_TABS: 283 selectTab(mTabs.get(position)); 284 break; 285 case NAVIGATION_MODE_LIST: 286 mActionView.setDropdownSelectedPosition(position); 287 break; 288 default: 289 throw new IllegalStateException( 290 "setSelectedNavigationIndex not valid for current navigation mode"); 291 } 292 } 293 294 public void removeAllTabs() { 295 cleanupTabs(); 296 } 297 298 private void cleanupTabs() { 299 if (mSelectedTab != null) { 300 selectTab(null); 301 } 302 mTabs.clear(); 303 mActionView.removeAllTabs(); 304 mSavedTabPosition = INVALID_POSITION; 305 } 306 307 public void setTitle(CharSequence title) { 308 mActionView.setTitle(title); 309 } 310 311 public void setSubtitle(CharSequence subtitle) { 312 mActionView.setSubtitle(subtitle); 313 } 314 315 public void setDisplayOptions(int options) { 316 mActionView.setDisplayOptions(options); 317 } 318 319 public void setDisplayOptions(int options, int mask) { 320 final int current = mActionView.getDisplayOptions(); 321 mActionView.setDisplayOptions((options & mask) | (current & ~mask)); 322 } 323 324 public void setBackgroundDrawable(Drawable d) { 325 mContainerView.setBackgroundDrawable(d); 326 } 327 328 public View getCustomView() { 329 return mActionView.getCustomNavigationView(); 330 } 331 332 public CharSequence getTitle() { 333 return mActionView.getTitle(); 334 } 335 336 public CharSequence getSubtitle() { 337 return mActionView.getSubtitle(); 338 } 339 340 public int getNavigationMode() { 341 return mActionView.getNavigationMode(); 342 } 343 344 public int getDisplayOptions() { 345 return mActionView.getDisplayOptions(); 346 } 347 348 public ActionMode startActionMode(ActionMode.Callback callback) { 349 if (mActionMode != null) { 350 mActionMode.finish(); 351 } 352 353 mUpperContextView.killMode(); 354 ActionMode mode = new ActionModeImpl(callback); 355 if (callback.onCreateActionMode(mode, mode.getMenu())) { 356 mode.invalidate(); 357 mUpperContextView.initForMode(mode); 358 animateTo(CONTEXT_VIEW); 359 if (mLowerContextView != null) { 360 // TODO animate this 361 mLowerContextView.setVisibility(View.VISIBLE); 362 } 363 mActionMode = mode; 364 return mode; 365 } 366 return null; 367 } 368 369 private void configureTab(Tab tab, int position) { 370 final TabImpl tabi = (TabImpl) tab; 371 final ActionBar.TabListener callback = tabi.getCallback(); 372 373 if (callback == null) { 374 throw new IllegalStateException("Action Bar Tab must have a Callback"); 375 } 376 377 tabi.setPosition(position); 378 mTabs.add(position, tabi); 379 380 final int count = mTabs.size(); 381 for (int i = position + 1; i < count; i++) { 382 mTabs.get(i).setPosition(i); 383 } 384 } 385 386 @Override 387 public void addTab(Tab tab) { 388 addTab(tab, mTabs.isEmpty()); 389 } 390 391 @Override 392 public void addTab(Tab tab, int position) { 393 addTab(tab, position, mTabs.isEmpty()); 394 } 395 396 @Override 397 public void addTab(Tab tab, boolean setSelected) { 398 mActionView.addTab(tab, setSelected); 399 configureTab(tab, mTabs.size()); 400 if (setSelected) { 401 selectTab(tab); 402 } 403 } 404 405 @Override 406 public void addTab(Tab tab, int position, boolean setSelected) { 407 mActionView.addTab(tab, position, setSelected); 408 configureTab(tab, position); 409 if (setSelected) { 410 selectTab(tab); 411 } 412 } 413 414 @Override 415 public Tab newTab() { 416 return new TabImpl(); 417 } 418 419 @Override 420 public void removeTab(Tab tab) { 421 removeTabAt(tab.getPosition()); 422 } 423 424 @Override 425 public void removeTabAt(int position) { 426 int selectedTabPosition = mSelectedTab != null 427 ? mSelectedTab.getPosition() : mSavedTabPosition; 428 mActionView.removeTabAt(position); 429 mTabs.remove(position); 430 431 final int newTabCount = mTabs.size(); 432 for (int i = position; i < newTabCount; i++) { 433 mTabs.get(i).setPosition(i); 434 } 435 436 if (selectedTabPosition == position) { 437 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); 438 } 439 } 440 441 @Override 442 public void selectTab(Tab tab) { 443 if (getNavigationMode() != NAVIGATION_MODE_TABS) { 444 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION; 445 return; 446 } 447 448 final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction() 449 .disallowAddToBackStack(); 450 451 if (mSelectedTab == tab) { 452 if (mSelectedTab != null) { 453 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans); 454 } 455 } else { 456 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION); 457 if (mSelectedTab != null) { 458 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans); 459 } 460 mSelectedTab = (TabImpl) tab; 461 if (mSelectedTab != null) { 462 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans); 463 } 464 } 465 466 if (!trans.isEmpty()) { 467 trans.commit(); 468 } 469 } 470 471 @Override 472 public Tab getSelectedTab() { 473 return mSelectedTab; 474 } 475 476 @Override 477 public int getHeight() { 478 return mActionView.getHeight(); 479 } 480 481 @Override 482 public void show() { 483 if (mCurrentAnim != null) { 484 mCurrentAnim.end(); 485 } 486 if (mContainerView.getVisibility() == View.VISIBLE) { 487 return; 488 } 489 mContainerView.setVisibility(View.VISIBLE); 490 mContainerView.setAlpha(0); 491 AnimatorSet anim = new AnimatorSet(); 492 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1)); 493 if (mContentView != null) { 494 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", 495 -mContainerView.getHeight(), 0)); 496 mContainerView.setTranslationY(-mContainerView.getHeight()); 497 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0)); 498 } 499 anim.addListener(mShowListener); 500 mCurrentAnim = anim; 501 anim.start(); 502 } 503 504 @Override 505 public void hide() { 506 if (mCurrentAnim != null) { 507 mCurrentAnim.end(); 508 } 509 if (mContainerView.getVisibility() == View.GONE) { 510 return; 511 } 512 mContainerView.setAlpha(1); 513 AnimatorSet anim = new AnimatorSet(); 514 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0)); 515 if (mContentView != null) { 516 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", 517 0, -mContainerView.getHeight())); 518 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 519 -mContainerView.getHeight())); 520 } 521 anim.addListener(mHideListener); 522 mCurrentAnim = anim; 523 anim.start(); 524 } 525 526 public boolean isShowing() { 527 return mContainerView.getVisibility() == View.VISIBLE; 528 } 529 530 private long animateTo(int viewIndex) { 531 show(); 532 533 AnimatorSet set = new AnimatorSet(); 534 535 final View targetChild = mContainerView.getChildAt(viewIndex); 536 targetChild.setVisibility(View.VISIBLE); 537 AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1)); 538 539 final int count = mContainerView.getChildCount(); 540 for (int i = 0; i < count; i++) { 541 final View child = mContainerView.getChildAt(i); 542 if (i == viewIndex) { 543 continue; 544 } 545 546 if (child.getVisibility() != View.GONE) { 547 Animator a = ObjectAnimator.ofFloat(child, "alpha", 0); 548 a.setInterpolator(sFadeOutInterpolator); 549 b.with(a); 550 } 551 } 552 553 set.addListener(mAfterAnimation[viewIndex]); 554 555 mCurrentAnim = set; 556 set.start(); 557 return set.getDuration(); 558 } 559 560 private void hideAllExcept(int viewIndex) { 561 final int count = mContainerView.getChildCount(); 562 for (int i = 0; i < count; i++) { 563 mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE); 564 } 565 } 566 567 /** 568 * @hide 569 */ 570 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback { 571 private ActionMode.Callback mCallback; 572 private MenuBuilder mMenu; 573 private WeakReference<View> mCustomView; 574 575 public ActionModeImpl(ActionMode.Callback callback) { 576 mCallback = callback; 577 mMenu = new MenuBuilder(mActionView.getContext()) 578 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 579 mMenu.setCallback(this); 580 } 581 582 @Override 583 public MenuInflater getMenuInflater() { 584 return new MenuInflater(mContext); 585 } 586 587 @Override 588 public Menu getMenu() { 589 return mMenu; 590 } 591 592 @Override 593 public void finish() { 594 if (mActionMode != this) { 595 // Not the active action mode - no-op 596 return; 597 } 598 599 mCallback.onDestroyActionMode(this); 600 mCallback = null; 601 animateTo(NORMAL_VIEW); 602 603 // Clear out the context mode views after the animation finishes 604 mUpperContextView.closeMode(); 605 if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) { 606 // TODO Animate this 607 mLowerContextView.setVisibility(View.GONE); 608 } 609 mActionMode = null; 610 } 611 612 @Override 613 public void invalidate() { 614 if (mCallback.onPrepareActionMode(this, mMenu)) { 615 // Refresh content in both context views 616 } 617 } 618 619 @Override 620 public void setCustomView(View view) { 621 mUpperContextView.setCustomView(view); 622 mCustomView = new WeakReference<View>(view); 623 } 624 625 @Override 626 public void setSubtitle(CharSequence subtitle) { 627 mUpperContextView.setSubtitle(subtitle); 628 } 629 630 @Override 631 public void setTitle(CharSequence title) { 632 mUpperContextView.setTitle(title); 633 } 634 635 @Override 636 public void setTitle(int resId) { 637 setTitle(mContext.getResources().getString(resId)); 638 } 639 640 @Override 641 public void setSubtitle(int resId) { 642 setSubtitle(mContext.getResources().getString(resId)); 643 } 644 645 @Override 646 public CharSequence getTitle() { 647 return mUpperContextView.getTitle(); 648 } 649 650 @Override 651 public CharSequence getSubtitle() { 652 return mUpperContextView.getSubtitle(); 653 } 654 655 @Override 656 public View getCustomView() { 657 return mCustomView != null ? mCustomView.get() : null; 658 } 659 660 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 661 if (mCallback != null) { 662 return mCallback.onActionItemClicked(this, item); 663 } else { 664 return false; 665 } 666 } 667 668 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 669 } 670 671 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 672 if (mCallback == null) { 673 return false; 674 } 675 676 if (!subMenu.hasVisibleItems()) { 677 return true; 678 } 679 680 new MenuPopupHelper(mContext, subMenu).show(); 681 return true; 682 } 683 684 public void onCloseSubMenu(SubMenuBuilder menu) { 685 } 686 687 public void onMenuModeChange(MenuBuilder menu) { 688 if (mCallback == null) { 689 return; 690 } 691 invalidate(); 692 mUpperContextView.openOverflowMenu(); 693 } 694 } 695 696 /** 697 * @hide 698 */ 699 public class TabImpl extends ActionBar.Tab { 700 private ActionBar.TabListener mCallback; 701 private Object mTag; 702 private Drawable mIcon; 703 private CharSequence mText; 704 private int mPosition; 705 private View mCustomView; 706 707 @Override 708 public Object getTag() { 709 return mTag; 710 } 711 712 @Override 713 public Tab setTag(Object tag) { 714 mTag = tag; 715 return this; 716 } 717 718 public ActionBar.TabListener getCallback() { 719 return mCallback; 720 } 721 722 @Override 723 public Tab setTabListener(ActionBar.TabListener callback) { 724 mCallback = callback; 725 return this; 726 } 727 728 @Override 729 public View getCustomView() { 730 return mCustomView; 731 } 732 733 @Override 734 public Tab setCustomView(View view) { 735 mCustomView = view; 736 return this; 737 } 738 739 @Override 740 public Tab setCustomView(int layoutResId) { 741 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null)); 742 } 743 744 @Override 745 public Drawable getIcon() { 746 return mIcon; 747 } 748 749 @Override 750 public int getPosition() { 751 return mPosition; 752 } 753 754 public void setPosition(int position) { 755 mPosition = position; 756 } 757 758 @Override 759 public CharSequence getText() { 760 return mText; 761 } 762 763 @Override 764 public Tab setIcon(Drawable icon) { 765 mIcon = icon; 766 return this; 767 } 768 769 @Override 770 public Tab setIcon(int resId) { 771 return setIcon(mContext.getResources().getDrawable(resId)); 772 } 773 774 @Override 775 public Tab setText(CharSequence text) { 776 mText = text; 777 return this; 778 } 779 780 @Override 781 public Tab setText(int resId) { 782 return setText(mContext.getResources().getText(resId)); 783 } 784 785 @Override 786 public void select() { 787 selectTab(this); 788 } 789 } 790 791 @Override 792 public void setCustomView(View view) { 793 mActionView.setCustomNavigationView(view); 794 } 795 796 @Override 797 public void setCustomView(View view, LayoutParams layoutParams) { 798 view.setLayoutParams(layoutParams); 799 mActionView.setCustomNavigationView(view); 800 } 801 802 @Override 803 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) { 804 mActionView.setDropdownAdapter(adapter); 805 mActionView.setCallback(callback); 806 } 807 808 @Override 809 public int getSelectedNavigationIndex() { 810 switch (mActionView.getNavigationMode()) { 811 case NAVIGATION_MODE_TABS: 812 return mSelectedTab != null ? mSelectedTab.getPosition() : -1; 813 case NAVIGATION_MODE_LIST: 814 return mActionView.getDropdownSelectedPosition(); 815 default: 816 return -1; 817 } 818 } 819 820 @Override 821 public int getNavigationItemCount() { 822 switch (mActionView.getNavigationMode()) { 823 case NAVIGATION_MODE_TABS: 824 return mTabs.size(); 825 case NAVIGATION_MODE_LIST: 826 SpinnerAdapter adapter = mActionView.getDropdownAdapter(); 827 return adapter != null ? adapter.getCount() : 0; 828 default: 829 return 0; 830 } 831 } 832 833 @Override 834 public int getTabCount() { 835 return mTabs.size(); 836 } 837 838 @Override 839 public void setNavigationMode(int mode) { 840 final int oldMode = mActionView.getNavigationMode(); 841 switch (oldMode) { 842 case NAVIGATION_MODE_TABS: 843 mSavedTabPosition = getSelectedNavigationIndex(); 844 selectTab(null); 845 break; 846 } 847 mActionView.setNavigationMode(mode); 848 switch (mode) { 849 case NAVIGATION_MODE_TABS: 850 if (mSavedTabPosition != INVALID_POSITION) { 851 setSelectedNavigationItem(mSavedTabPosition); 852 mSavedTabPosition = INVALID_POSITION; 853 } 854 break; 855 } 856 } 857 858 @Override 859 public Tab getTabAt(int index) { 860 return mTabs.get(index); 861 } 862 863 /** 864 * This fragment is added when we're keeping a back stack in a tab switch 865 * transaction. We use it to change the selected tab in the action bar view 866 * when we back out. 867 */ 868 private class SwitchSelectedTabViewFragment extends Fragment { 869 private int mSelectedTabIndex; 870 871 public SwitchSelectedTabViewFragment(int oldSelectedTab) { 872 mSelectedTabIndex = oldSelectedTab; 873 } 874 875 @Override 876 public void onDetach() { 877 if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) { 878 mActionView.setTabSelected(mSelectedTabIndex); 879 } 880 } 881 } 882} 883