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