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