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