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