ActionBarImpl.java revision 73e371ff7a23d814c0da10edf40a5a4f31b26b33
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 setTitle(int resId) { 242 setTitle(mContext.getString(resId)); 243 } 244 245 @Override 246 public void setSubtitle(int resId) { 247 setSubtitle(mContext.getString(resId)); 248 } 249 250 public void setCustomNavigationMode(View view) { 251 cleanupTabs(); 252 setCustomView(view); 253 setDisplayOptions(DISPLAY_SHOW_CUSTOM, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE); 254 mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD); 255 mActionView.setCallback(null); 256 } 257 258 public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback) { 259 setDropdownNavigationMode(adapter, callback, -1); 260 } 261 262 public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback, 263 int defaultSelectedPosition) { 264 cleanupTabs(); 265 setDisplayOptions(0, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE); 266 mActionView.setNavigationMode(NAVIGATION_MODE_LIST); 267 setListNavigationCallbacks(adapter, callback); 268 if (defaultSelectedPosition >= 0) { 269 mActionView.setDropdownSelectedPosition(defaultSelectedPosition); 270 } 271 } 272 273 public void setStandardNavigationMode() { 274 cleanupTabs(); 275 setDisplayOptions(DISPLAY_SHOW_TITLE, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM); 276 mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD); 277 mActionView.setCallback(null); 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 int getSelectedNavigationItem() { 295 return getSelectedNavigationIndex(); 296 } 297 298 public void removeAllTabs() { 299 cleanupTabs(); 300 } 301 302 private void cleanupTabs() { 303 if (mSelectedTab != null) { 304 selectTab(null); 305 } 306 mTabs.clear(); 307 mActionView.removeAllTabs(); 308 mSavedTabPosition = INVALID_POSITION; 309 } 310 311 public void setTitle(CharSequence title) { 312 mActionView.setTitle(title); 313 } 314 315 public void setSubtitle(CharSequence subtitle) { 316 mActionView.setSubtitle(subtitle); 317 } 318 319 public void setDisplayOptions(int options) { 320 mActionView.setDisplayOptions(options); 321 } 322 323 public void setDisplayOptions(int options, int mask) { 324 final int current = mActionView.getDisplayOptions(); 325 mActionView.setDisplayOptions((options & mask) | (current & ~mask)); 326 } 327 328 public void setBackgroundDrawable(Drawable d) { 329 mContainerView.setBackgroundDrawable(d); 330 } 331 332 public View getCustomNavigationView() { 333 return getCustomView(); 334 } 335 336 public View getCustomView() { 337 return mActionView.getCustomNavigationView(); 338 } 339 340 public CharSequence getTitle() { 341 return mActionView.getTitle(); 342 } 343 344 public CharSequence getSubtitle() { 345 return mActionView.getSubtitle(); 346 } 347 348 public int getNavigationMode() { 349 return mActionView.getNavigationMode(); 350 } 351 352 public int getDisplayOptions() { 353 return mActionView.getDisplayOptions(); 354 } 355 356 public ActionMode startActionMode(ActionMode.Callback callback) { 357 if (mActionMode != null) { 358 mActionMode.finish(); 359 } 360 361 ActionMode mode = new ActionModeImpl(callback); 362 if (callback.onCreateActionMode(mode, mode.getMenu())) { 363 mode.invalidate(); 364 mUpperContextView.initForMode(mode); 365 animateTo(CONTEXT_VIEW); 366 if (mLowerContextView != null) { 367 // TODO animate this 368 mLowerContextView.setVisibility(View.VISIBLE); 369 } 370 mActionMode = mode; 371 return mode; 372 } 373 return null; 374 } 375 376 private void configureTab(Tab tab, int position) { 377 final TabImpl tabi = (TabImpl) tab; 378 final ActionBar.TabListener callback = tabi.getCallback(); 379 380 if (callback == null) { 381 throw new IllegalStateException("Action Bar Tab must have a Callback"); 382 } 383 384 tabi.setPosition(position); 385 mTabs.add(position, tabi); 386 387 final int count = mTabs.size(); 388 for (int i = position + 1; i < count; i++) { 389 mTabs.get(i).setPosition(i); 390 } 391 } 392 393 @Override 394 public void addTab(Tab tab) { 395 addTab(tab, mTabs.isEmpty()); 396 } 397 398 @Override 399 public void addTab(Tab tab, int position) { 400 addTab(tab, position, mTabs.isEmpty()); 401 } 402 403 @Override 404 public void addTab(Tab tab, boolean setSelected) { 405 mActionView.addTab(tab, setSelected); 406 configureTab(tab, mTabs.size()); 407 if (setSelected) { 408 selectTab(tab); 409 } 410 } 411 412 @Override 413 public void addTab(Tab tab, int position, boolean setSelected) { 414 mActionView.addTab(tab, position, setSelected); 415 configureTab(tab, position); 416 if (setSelected) { 417 selectTab(tab); 418 } 419 } 420 421 @Override 422 public Tab newTab() { 423 return new TabImpl(); 424 } 425 426 @Override 427 public void removeTab(Tab tab) { 428 removeTabAt(tab.getPosition()); 429 } 430 431 @Override 432 public void removeTabAt(int position) { 433 int selectedTabPosition = mSelectedTab != null 434 ? mSelectedTab.getPosition() : mSavedTabPosition; 435 mActionView.removeTabAt(position); 436 mTabs.remove(position); 437 438 final int newTabCount = mTabs.size(); 439 for (int i = position; i < newTabCount; i++) { 440 mTabs.get(i).setPosition(i); 441 } 442 443 if (selectedTabPosition == position) { 444 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); 445 } 446 } 447 448 @Override 449 public void setTabNavigationMode() { 450 if (mActivity == null) { 451 throw new IllegalStateException( 452 "Tab navigation mode cannot be used outside of an Activity"); 453 } 454 setDisplayOptions(0, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM); 455 mActionView.setNavigationMode(NAVIGATION_MODE_TABS); 456 } 457 458 @Override 459 public void selectTab(Tab tab) { 460 if (getNavigationMode() != NAVIGATION_MODE_TABS) { 461 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION; 462 return; 463 } 464 465 final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction() 466 .disallowAddToBackStack(); 467 468 if (mSelectedTab == tab) { 469 if (mSelectedTab != null) { 470 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans); 471 } 472 } else { 473 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION); 474 if (mSelectedTab != null) { 475 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans); 476 } 477 mSelectedTab = (TabImpl) tab; 478 if (mSelectedTab != null) { 479 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans); 480 } 481 } 482 483 if (!trans.isEmpty()) { 484 trans.commit(); 485 } 486 } 487 488 @Override 489 public Tab getSelectedTab() { 490 return mSelectedTab; 491 } 492 493 @Override 494 public int getHeight() { 495 return mActionView.getHeight(); 496 } 497 498 @Override 499 public void show() { 500 if (mContainerView.getVisibility() == View.VISIBLE) { 501 return; 502 } 503 if (mCurrentAnim != null) { 504 mCurrentAnim.end(); 505 } 506 mContainerView.setVisibility(View.VISIBLE); 507 mContainerView.setAlpha(0); 508 AnimatorSet anim = new AnimatorSet(); 509 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1)); 510 if (mContentView != null) { 511 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", 512 -mContainerView.getHeight(), 0)); 513 mContainerView.setTranslationY(-mContainerView.getHeight()); 514 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0)); 515 } 516 anim.addListener(mShowListener); 517 mCurrentAnim = anim; 518 anim.start(); 519 } 520 521 @Override 522 public void hide() { 523 if (mCurrentAnim != null) { 524 mCurrentAnim.end(); 525 } 526 if (mContainerView.getVisibility() == View.GONE) { 527 return; 528 } 529 mContainerView.setAlpha(1); 530 AnimatorSet anim = new AnimatorSet(); 531 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0)); 532 if (mContentView != null) { 533 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", 534 0, -mContainerView.getHeight())); 535 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 536 -mContainerView.getHeight())); 537 } 538 anim.addListener(mHideListener); 539 mCurrentAnim = anim; 540 anim.start(); 541 } 542 543 public boolean isShowing() { 544 return mContainerView.getVisibility() == View.VISIBLE; 545 } 546 547 private long animateTo(int viewIndex) { 548 show(); 549 550 AnimatorSet set = new AnimatorSet(); 551 552 final View targetChild = mContainerView.getChildAt(viewIndex); 553 targetChild.setVisibility(View.VISIBLE); 554 AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1)); 555 556 final int count = mContainerView.getChildCount(); 557 for (int i = 0; i < count; i++) { 558 final View child = mContainerView.getChildAt(i); 559 if (i == viewIndex) { 560 continue; 561 } 562 563 if (child.getVisibility() != View.GONE) { 564 Animator a = ObjectAnimator.ofFloat(child, "alpha", 0); 565 a.setInterpolator(sFadeOutInterpolator); 566 b.with(a); 567 } 568 } 569 570 set.addListener(mAfterAnimation[viewIndex]); 571 572 mCurrentAnim = set; 573 set.start(); 574 return set.getDuration(); 575 } 576 577 private void hideAllExcept(int viewIndex) { 578 final int count = mContainerView.getChildCount(); 579 for (int i = 0; i < count; i++) { 580 mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE); 581 } 582 } 583 584 /** 585 * @hide 586 */ 587 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback { 588 private ActionMode.Callback mCallback; 589 private MenuBuilder mMenu; 590 private WeakReference<View> mCustomView; 591 592 public ActionModeImpl(ActionMode.Callback callback) { 593 mCallback = callback; 594 mMenu = new MenuBuilder(mActionView.getContext()) 595 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 596 mMenu.setCallback(this); 597 } 598 599 @Override 600 public MenuInflater getMenuInflater() { 601 return new MenuInflater(mContext); 602 } 603 604 @Override 605 public Menu getMenu() { 606 return mMenu; 607 } 608 609 @Override 610 public void finish() { 611 if (mActionMode != this) { 612 // Not the active action mode - no-op 613 return; 614 } 615 616 mCallback.onDestroyActionMode(this); 617 mCallback = null; 618 animateTo(NORMAL_VIEW); 619 620 // Clear out the context mode views after the animation finishes 621 mUpperContextView.closeMode(); 622 if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) { 623 // TODO Animate this 624 mLowerContextView.setVisibility(View.GONE); 625 } 626 mActionMode = null; 627 } 628 629 @Override 630 public void invalidate() { 631 if (mCallback.onPrepareActionMode(this, mMenu)) { 632 // Refresh content in both context views 633 } 634 } 635 636 @Override 637 public void setCustomView(View view) { 638 mUpperContextView.setCustomView(view); 639 mCustomView = new WeakReference<View>(view); 640 } 641 642 @Override 643 public void setSubtitle(CharSequence subtitle) { 644 mUpperContextView.setSubtitle(subtitle); 645 } 646 647 @Override 648 public void setTitle(CharSequence title) { 649 mUpperContextView.setTitle(title); 650 } 651 652 @Override 653 public void setTitle(int resId) { 654 setTitle(mActivity.getString(resId)); 655 } 656 657 @Override 658 public void setSubtitle(int resId) { 659 setSubtitle(mActivity.getString(resId)); 660 } 661 662 @Override 663 public CharSequence getTitle() { 664 return mUpperContextView.getTitle(); 665 } 666 667 @Override 668 public CharSequence getSubtitle() { 669 return mUpperContextView.getSubtitle(); 670 } 671 672 @Override 673 public View getCustomView() { 674 return mCustomView != null ? mCustomView.get() : null; 675 } 676 677 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 678 if (mCallback != null) { 679 return mCallback.onActionItemClicked(this, item); 680 } else { 681 return false; 682 } 683 } 684 685 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 686 } 687 688 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 689 if (mCallback == null) { 690 return false; 691 } 692 693 if (!subMenu.hasVisibleItems()) { 694 return true; 695 } 696 697 new MenuPopupHelper(mContext, subMenu).show(); 698 return true; 699 } 700 701 public void onCloseSubMenu(SubMenuBuilder menu) { 702 } 703 704 public void onMenuModeChange(MenuBuilder menu) { 705 if (mCallback == null) { 706 return; 707 } 708 invalidate(); 709 mUpperContextView.openOverflowMenu(); 710 } 711 } 712 713 /** 714 * @hide 715 */ 716 public class TabImpl extends ActionBar.Tab { 717 private ActionBar.TabListener mCallback; 718 private Object mTag; 719 private Drawable mIcon; 720 private CharSequence mText; 721 private int mPosition; 722 private View mCustomView; 723 724 @Override 725 public Object getTag() { 726 return mTag; 727 } 728 729 @Override 730 public Tab setTag(Object tag) { 731 mTag = tag; 732 return this; 733 } 734 735 public ActionBar.TabListener getCallback() { 736 return mCallback; 737 } 738 739 @Override 740 public Tab setTabListener(ActionBar.TabListener callback) { 741 mCallback = callback; 742 return this; 743 } 744 745 @Override 746 public View getCustomView() { 747 return mCustomView; 748 } 749 750 @Override 751 public Tab setCustomView(View view) { 752 mCustomView = view; 753 return this; 754 } 755 756 @Override 757 public Tab setCustomView(int layoutResId) { 758 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null)); 759 } 760 761 @Override 762 public Drawable getIcon() { 763 return mIcon; 764 } 765 766 @Override 767 public int getPosition() { 768 return mPosition; 769 } 770 771 public void setPosition(int position) { 772 mPosition = position; 773 } 774 775 @Override 776 public CharSequence getText() { 777 return mText; 778 } 779 780 @Override 781 public Tab setIcon(Drawable icon) { 782 mIcon = icon; 783 return this; 784 } 785 786 @Override 787 public Tab setIcon(int resId) { 788 return setIcon(mContext.getResources().getDrawable(resId)); 789 } 790 791 @Override 792 public Tab setText(CharSequence text) { 793 mText = text; 794 return this; 795 } 796 797 @Override 798 public Tab setText(int resId) { 799 return setText(mContext.getResources().getText(resId)); 800 } 801 802 @Override 803 public void select() { 804 selectTab(this); 805 } 806 } 807 808 @Override 809 public void setCustomView(View view) { 810 mActionView.setCustomNavigationView(view); 811 } 812 813 @Override 814 public void setCustomView(View view, LayoutParams layoutParams) { 815 view.setLayoutParams(layoutParams); 816 mActionView.setCustomNavigationView(view); 817 } 818 819 @Override 820 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) { 821 mActionView.setDropdownAdapter(adapter); 822 mActionView.setCallback(callback); 823 } 824 825 @Override 826 public int getSelectedNavigationIndex() { 827 switch (mActionView.getNavigationMode()) { 828 case NAVIGATION_MODE_TABS: 829 return mSelectedTab != null ? mSelectedTab.getPosition() : -1; 830 case NAVIGATION_MODE_LIST: 831 return mActionView.getDropdownSelectedPosition(); 832 default: 833 return -1; 834 } 835 } 836 837 @Override 838 public int getNavigationItemCount() { 839 switch (mActionView.getNavigationMode()) { 840 case NAVIGATION_MODE_TABS: 841 return mTabs.size(); 842 case NAVIGATION_MODE_LIST: 843 SpinnerAdapter adapter = mActionView.getDropdownAdapter(); 844 return adapter != null ? adapter.getCount() : 0; 845 default: 846 return 0; 847 } 848 } 849 850 @Override 851 public int getTabCount() { 852 return mTabs.size(); 853 } 854 855 @Override 856 public void setNavigationMode(int mode) { 857 final int oldMode = mActionView.getNavigationMode(); 858 switch (oldMode) { 859 case NAVIGATION_MODE_TABS: 860 mSavedTabPosition = getSelectedNavigationIndex(); 861 selectTab(null); 862 break; 863 } 864 mActionView.setNavigationMode(mode); 865 switch (mode) { 866 case NAVIGATION_MODE_TABS: 867 if (mSavedTabPosition != INVALID_POSITION) { 868 setSelectedNavigationItem(mSavedTabPosition); 869 mSavedTabPosition = INVALID_POSITION; 870 } 871 break; 872 } 873 } 874 875 @Override 876 public Tab getTabAt(int index) { 877 return mTabs.get(index); 878 } 879 880 /** 881 * This fragment is added when we're keeping a back stack in a tab switch 882 * transaction. We use it to change the selected tab in the action bar view 883 * when we back out. 884 */ 885 private class SwitchSelectedTabViewFragment extends Fragment { 886 private int mSelectedTabIndex; 887 888 public SwitchSelectedTabViewFragment(int oldSelectedTab) { 889 mSelectedTabIndex = oldSelectedTab; 890 } 891 892 @Override 893 public void onDetach() { 894 if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) { 895 mActionView.setTabSelected(mSelectedTabIndex); 896 } 897 } 898 } 899} 900