1bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/*
2bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Copyright (C) 2011 The Android Open Source Project
3bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
4bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * you may not use this file except in compliance with the License.
6bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * You may obtain a copy of the License at
7bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
8bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
10bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Unless required by applicable law or agreed to in writing, software
11bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * See the License for the specific language governing permissions and
14bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * limitations under the License.
15bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */
1666698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banespackage android.support.v7.widget;
17bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
18bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context;
19bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Configuration;
20bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.graphics.drawable.Drawable;
2149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.os.Build;
22c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo;
2349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.GravityCompat;
2449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewCompat;
2549c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewPropertyAnimatorCompat;
2649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewPropertyAnimatorListener;
27da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.app.ActionBar;
28da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R;
2966698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.ActionBarPolicy;
3049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.text.TextUtils;
31bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.text.TextUtils.TruncateAt;
32bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.Gravity;
33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View;
34bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewGroup;
35bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewParent;
3649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.accessibility.AccessibilityEvent;
3749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.accessibility.AccessibilityNodeInfo;
3849c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.animation.DecelerateInterpolator;
3949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.animation.Interpolator;
40f933672168f6deff5e3636584bec735416b5a93bChris Banesimport android.widget.AdapterView;
41bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.BaseAdapter;
42bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.HorizontalScrollView;
43bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.ImageView;
44bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.ListView;
45f933672168f6deff5e3636584bec735416b5a93bChris Banesimport android.widget.Spinner;
46bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.TextView;
4749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.Toast;
48bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
49c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport static android.support.annotation.RestrictTo.Scope.GROUP_ID;
50c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette
51bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/**
5220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * This widget implements the dynamic action bar tab behavior that can change across different
5320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * configurations or circumstances.
5489208232f3b5d1451408d787872504a190bc7ee0Chris Banes *
5589208232f3b5d1451408d787872504a190bc7ee0Chris Banes * @hide
56bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */
57c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette@RestrictTo(GROUP_ID)
58bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellpublic class ScrollingTabContainerView extends HorizontalScrollView
59f933672168f6deff5e3636584bec735416b5a93bChris Banes        implements AdapterView.OnItemSelectedListener {
6020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
61ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private static final String TAG = "ScrollingTabContainerView";
62ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    Runnable mTabSelector;
63ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private TabClickListener mTabClickListener;
64bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
652c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas    LinearLayoutCompat mTabLayout;
66f933672168f6deff5e3636584bec735416b5a93bChris Banes    private Spinner mTabSpinner;
67ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private boolean mAllowCollapse;
68bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
69ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    int mMaxTabWidth;
70ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    int mStackedTabMaxWidth;
71ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private int mContentHeight;
72ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private int mSelectedTabIndex;
73bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
7449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    protected ViewPropertyAnimatorCompat mVisibilityAnim;
7549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
7649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
7749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private static final Interpolator sAlphaInterpolator = new DecelerateInterpolator();
7849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
7949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private static final int FADE_DURATION = 200;
8049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
81ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public ScrollingTabContainerView(Context context) {
82ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        super(context);
83624d7ed5e2d6dc7a937468dda7bef1f65cd765d7Chris Banes
84ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        setHorizontalScrollBarEnabled(false);
85bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
86ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        ActionBarPolicy abp = ActionBarPolicy.get(context);
87ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        setContentHeight(abp.getTabContainerHeight());
88ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mStackedTabMaxWidth = abp.getStackedTabMaxWidth();
89bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
9049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mTabLayout = createTabLayout();
91ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
9249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                ViewGroup.LayoutParams.MATCH_PARENT));
93bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
94ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
95ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
96ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
97ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
98ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
99ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        setFillViewport(lockedExpanded);
100ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
101ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final int childCount = mTabLayout.getChildCount();
102ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (childCount > 1 &&
10320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
104ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (childCount > 2) {
105ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f);
106ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            } else {
107ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
108ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
109ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mMaxTabWidth = Math.min(mMaxTabWidth, mStackedTabMaxWidth);
110ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        } else {
111ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mMaxTabWidth = -1;
112ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
113ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
114ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY);
115ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
116ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final boolean canCollapse = !lockedExpanded && mAllowCollapse;
117ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
118ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (canCollapse) {
119ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // See if we should expand
120ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec);
121ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) {
122ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                performCollapse();
123ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            } else {
124ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                performExpand();
125ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
126ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        } else {
127ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            performExpand();
128ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final int oldWidth = getMeasuredWidth();
131ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
132ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final int newWidth = getMeasuredWidth();
133ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
134ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (lockedExpanded && oldWidth != newWidth) {
135ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // Recenter the tab display if we're at a new (scrollable) size.
136ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            setTabSelected(mSelectedTabIndex);
137ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
138bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
139ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
140ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    /**
14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Indicates whether this view is collapsed into a dropdown menu instead
14249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * of traditional tabs.
143ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani     * @return true if showing as a spinner
144ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani     */
145ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private boolean isCollapsed() {
146ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return mTabSpinner != null && mTabSpinner.getParent() == this;
147bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
148ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
149ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void setAllowCollapse(boolean allowCollapse) {
150ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mAllowCollapse = allowCollapse;
151bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
152ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
153ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private void performCollapse() {
15449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (isCollapsed()) return;
155ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
156ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSpinner == null) {
157ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTabSpinner = createSpinner();
158ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
159ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        removeView(mTabLayout);
160ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                ViewGroup.LayoutParams.MATCH_PARENT));
162ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSpinner.getAdapter() == null) {
163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTabSpinner.setAdapter(new TabAdapter());
164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSelector != null) {
166ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            removeCallbacks(mTabSelector);
167ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTabSelector = null;
168ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
169ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mTabSpinner.setSelection(mSelectedTabIndex);
170bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
171ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
172ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private boolean performExpand() {
17349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (!isCollapsed()) return false;
174ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
175ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        removeView(mTabSpinner);
176ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
17749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                ViewGroup.LayoutParams.MATCH_PARENT));
178ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        setTabSelected(mTabSpinner.getSelectedItemPosition());
179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
180bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
182ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void setTabSelected(int position) {
183ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mSelectedTabIndex = position;
184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final int tabCount = mTabLayout.getChildCount();
185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        for (int i = 0; i < tabCount; i++) {
186ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final View child = mTabLayout.getChildAt(i);
187ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final boolean isSelected = i == position;
188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            child.setSelected(isSelected);
189ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (isSelected) {
190ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                animateToTab(position);
191ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
192ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
193b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes        if (mTabSpinner != null && position >= 0) {
194b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes            mTabSpinner.setSelection(position);
195b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes        }
196bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
197bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
198ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void setContentHeight(int contentHeight) {
199ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mContentHeight = contentHeight;
200ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        requestLayout();
201bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
202ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
20349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private LinearLayoutCompat createTabLayout() {
20449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final LinearLayoutCompat tabLayout = new LinearLayoutCompat(getContext(), null,
20549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                R.attr.actionBarTabBarStyle);
20649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        tabLayout.setMeasureWithLargestChildEnabled(true);
20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        tabLayout.setGravity(Gravity.CENTER);
20849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        tabLayout.setLayoutParams(new LinearLayoutCompat.LayoutParams(
20949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                LinearLayoutCompat.LayoutParams.WRAP_CONTENT, LinearLayoutCompat.LayoutParams.MATCH_PARENT));
21049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return tabLayout;
21149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
21249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
213f933672168f6deff5e3636584bec735416b5a93bChris Banes    private Spinner createSpinner() {
214f933672168f6deff5e3636584bec735416b5a93bChris Banes        final Spinner spinner = new AppCompatSpinner(getContext(), null,
21520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                R.attr.actionDropDownStyle);
21649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        spinner.setLayoutParams(new LinearLayoutCompat.LayoutParams(
217f933672168f6deff5e3636584bec735416b5a93bChris Banes                LinearLayoutCompat.LayoutParams.WRAP_CONTENT,
218f933672168f6deff5e3636584bec735416b5a93bChris Banes                LinearLayoutCompat.LayoutParams.MATCH_PARENT));
219f933672168f6deff5e3636584bec735416b5a93bChris Banes        spinner.setOnItemSelectedListener(this);
220ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return spinner;
221bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
222ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
223dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas    @Override
224ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    protected void onConfigurationChanged(Configuration newConfig) {
22564dbe1d454f1190b3cd8426d09b9119949a10709Kirill Grouchnikov        super.onConfigurationChanged(newConfig);
22649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
227ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        ActionBarPolicy abp = ActionBarPolicy.get(getContext());
228ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Action bar can change size on configuration changes.
229ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Reread the desired height from the theme-specified style.
230ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        setContentHeight(abp.getTabContainerHeight());
231ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mStackedTabMaxWidth = abp.getStackedTabMaxWidth();
232bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
233ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
23449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public void animateToVisibility(int visibility) {
23549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (mVisibilityAnim != null) {
23649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mVisibilityAnim.cancel();
23749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
23849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (visibility == VISIBLE) {
23949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (getVisibility() != VISIBLE) {
24049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                ViewCompat.setAlpha(this, 0f);
24149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
24249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
24349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f);
24449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.setDuration(FADE_DURATION);
24549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
24649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.setInterpolator(sAlphaInterpolator);
24749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
24849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.start();
24949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        } else {
25049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(0f);
25149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.setDuration(FADE_DURATION);
25249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
25349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.setInterpolator(sAlphaInterpolator);
25449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
25549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            anim.start();
25649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
25749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
25849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
259ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void animateToTab(final int position) {
260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final View tabView = mTabLayout.getChildAt(position);
261ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSelector != null) {
262ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            removeCallbacks(mTabSelector);
263ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
264ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mTabSelector = new Runnable() {
265dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas            @Override
266ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            public void run() {
267ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
268ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                smoothScrollTo(scrollPos, 0);
269ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mTabSelector = null;
270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        };
272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        post(mTabSelector);
273bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onAttachedToWindow() {
277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        super.onAttachedToWindow();
278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSelector != null) {
279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // Re-post the selector we saved
280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            post(mTabSelector);
281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
282bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onDetachedFromWindow() {
286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        super.onDetachedFromWindow();
287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSelector != null) {
288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            removeCallbacks(mTabSelector);
289ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
290bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
2922c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas    TabView createTabView(ActionBar.Tab tab, boolean forAdapter) {
29349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final TabView tabView = new TabView(getContext(), tab, forAdapter);
294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (forAdapter) {
295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            tabView.setBackgroundDrawable(null);
29649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT,
29720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    mContentHeight));
298ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        } else {
299ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            tabView.setFocusable(true);
300ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
301ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mTabClickListener == null) {
302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mTabClickListener = new TabClickListener();
303ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
304ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            tabView.setOnClickListener(mTabClickListener);
305ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
306ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return tabView;
307bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
308bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void addTab(ActionBar.Tab tab, boolean setSelected) {
310ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        TabView tabView = createTabView(tab, false);
31149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mTabLayout.addView(tabView, new LinearLayoutCompat.LayoutParams(0,
31249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                LayoutParams.MATCH_PARENT, 1));
313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSpinner != null) {
314ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
315ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
316ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (setSelected) {
317ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            tabView.setSelected(true);
318ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
319ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mAllowCollapse) {
320ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            requestLayout();
321ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
322bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
323ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
324ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void addTab(ActionBar.Tab tab, int position, boolean setSelected) {
325ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final TabView tabView = createTabView(tab, false);
32649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mTabLayout.addView(tabView, position, new LinearLayoutCompat.LayoutParams(
32749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                0, LayoutParams.MATCH_PARENT, 1));
328ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSpinner != null) {
329ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
330ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
331ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (setSelected) {
332ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            tabView.setSelected(true);
333ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
334ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mAllowCollapse) {
335ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            requestLayout();
336ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
337bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
338bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
339ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void updateTab(int position) {
340ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        ((TabView) mTabLayout.getChildAt(position)).update();
341ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSpinner != null) {
342ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
343ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
344ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mAllowCollapse) {
345ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            requestLayout();
346ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
347bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
348ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
349ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void removeTabAt(int position) {
350ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mTabLayout.removeViewAt(position);
351ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSpinner != null) {
352ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
353ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
354ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mAllowCollapse) {
355ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            requestLayout();
356ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
357bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
358bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
359ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void removeAllTabs() {
360ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mTabLayout.removeAllViews();
361ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTabSpinner != null) {
362ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
363ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
364ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mAllowCollapse) {
365ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            requestLayout();
366ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
367bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
368ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
369ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
370f933672168f6deff5e3636584bec735416b5a93bChris Banes    public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
371ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        TabView tabView = (TabView) view;
372ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        tabView.getTab().select();
373bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
374bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
375f933672168f6deff5e3636584bec735416b5a93bChris Banes    @Override
376f933672168f6deff5e3636584bec735416b5a93bChris Banes    public void onNothingSelected(AdapterView<?> adapterView) {
377f933672168f6deff5e3636584bec735416b5a93bChris Banes        // no-op
378f933672168f6deff5e3636584bec735416b5a93bChris Banes    }
379f933672168f6deff5e3636584bec735416b5a93bChris Banes
38049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private class TabView extends LinearLayoutCompat implements OnLongClickListener {
381469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        private final int[] BG_ATTRS = {
382469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                android.R.attr.background
383469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        };
384469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
385ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private ActionBar.Tab mTab;
386ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private TextView mTextView;
387ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private ImageView mIconView;
388ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private View mCustomView;
389bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
39049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public TabView(Context context, ActionBar.Tab tab, boolean forList) {
39149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            super(context, null, R.attr.actionBarTabStyle);
392ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTab = tab;
39334b5c9580dd01b4428ab2c5990add571eaab6b13Trevor Johns
394469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, null, BG_ATTRS,
395469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                    R.attr.actionBarTabStyle, 0);
396469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (a.hasValue(0)) {
397469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                setBackgroundDrawable(a.getDrawable(0));
398469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
399469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            a.recycle();
400469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
401ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (forList) {
40249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                setGravity(GravityCompat.START | Gravity.CENTER_VERTICAL);
403ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
404bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
405ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            update();
406ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
407bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
408ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public void bindTab(ActionBar.Tab tab) {
409ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTab = tab;
410ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            update();
411ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
412bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
413ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        @Override
41449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void setSelected(boolean selected) {
41549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final boolean changed = (isSelected() != selected);
41649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            super.setSelected(selected);
41749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (changed && selected) {
41849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
41949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
42049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
42149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
42249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
42349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
42449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            super.onInitializeAccessibilityEvent(event);
42549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // This view masquerades as an action bar tab.
42649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            event.setClassName(ActionBar.Tab.class.getName());
42749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
42849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
42949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
43049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
43149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            super.onInitializeAccessibilityNodeInfo(info);
43249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
43349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (Build.VERSION.SDK_INT >= 14) {
43449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                // This view masquerades as an action bar tab.
43549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                info.setClassName(ActionBar.Tab.class.getName());
43649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
43749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
43849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
43949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
440ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
441ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
442bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
443ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // Re-measure if we went beyond our maximum size.
44449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (mMaxTabWidth > 0 && getMeasuredWidth() > mMaxTabWidth) {
44549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxTabWidth, MeasureSpec.EXACTLY),
44620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        heightMeasureSpec);
447ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
448ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
449bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
450ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public void update() {
451ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final ActionBar.Tab tab = mTab;
452ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final View custom = tab.getCustomView();
453ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (custom != null) {
454ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final ViewParent customParent = custom.getParent();
455ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (customParent != this) {
45649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (customParent != null) ((ViewGroup) customParent).removeView(custom);
457ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    addView(custom);
458ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
459ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mCustomView = custom;
46049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (mTextView != null) mTextView.setVisibility(GONE);
461ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (mIconView != null) {
462ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mIconView.setVisibility(GONE);
463ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mIconView.setImageDrawable(null);
464ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
465ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            } else {
466ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (mCustomView != null) {
467ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    removeView(mCustomView);
468ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mCustomView = null;
469ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
470ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
471ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final Drawable icon = tab.getIcon();
472ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final CharSequence text = tab.getText();
473ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
474ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (icon != null) {
475ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    if (mIconView == null) {
47619ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        ImageView iconView = new AppCompatImageView(getContext());
477ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
47820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                                LayoutParams.WRAP_CONTENT);
479ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        lp.gravity = Gravity.CENTER_VERTICAL;
480ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        iconView.setLayoutParams(lp);
481ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        addView(iconView, 0);
482ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        mIconView = iconView;
483ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    }
484ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mIconView.setImageDrawable(icon);
485ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mIconView.setVisibility(VISIBLE);
486ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                } else if (mIconView != null) {
487ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mIconView.setVisibility(GONE);
488ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mIconView.setImageDrawable(null);
489ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
490ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
49149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                final boolean hasText = !TextUtils.isEmpty(text);
49249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (hasText) {
493ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    if (mTextView == null) {
4942cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes                        TextView textView = new AppCompatTextView(getContext(), null,
49520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                                R.attr.actionBarTabTextStyle);
496ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        textView.setEllipsize(TruncateAt.END);
497ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
49820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                                LayoutParams.WRAP_CONTENT);
499ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        lp.gravity = Gravity.CENTER_VERTICAL;
500ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        textView.setLayoutParams(lp);
501ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        addView(textView);
502ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        mTextView = textView;
503ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    }
504ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mTextView.setText(text);
505ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mTextView.setVisibility(VISIBLE);
506ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                } else if (mTextView != null) {
507ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mTextView.setVisibility(GONE);
508ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mTextView.setText(null);
509ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
510ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
511ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (mIconView != null) {
512ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mIconView.setContentDescription(tab.getContentDescription());
513ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
51449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
51549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
51649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    setOnLongClickListener(this);
51749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                } else {
51849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    setOnLongClickListener(null);
51949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    setLongClickable(false);
52049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                }
521ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
522ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
523bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
524dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas        @Override
52549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public boolean onLongClick(View v) {
52649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int[] screenPos = new int[2];
52749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            getLocationOnScreen(screenPos);
52849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
52949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final Context context = getContext();
53049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int width = getWidth();
53149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int height = getHeight();
53249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
53349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
53449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
53549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    Toast.LENGTH_SHORT);
53649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Show under the tab
53749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
53849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    (screenPos[0] + width / 2) - screenWidth / 2, height);
53949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
54049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            cheatSheet.show();
54149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return true;
54249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
54349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
544ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public ActionBar.Tab getTab() {
545ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return mTab;
546ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
547bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
548bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
549ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private class TabAdapter extends BaseAdapter {
5502c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        TabAdapter() {
5512c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        }
5522c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas
553ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        @Override
554ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public int getCount() {
555ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return mTabLayout.getChildCount();
556ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
557bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
558ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        @Override
559ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public Object getItem(int position) {
560ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return ((TabView) mTabLayout.getChildAt(position)).getTab();
561ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
562bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
563ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        @Override
564ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public long getItemId(int position) {
565ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return position;
566ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
567bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
568ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        @Override
569ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public View getView(int position, View convertView, ViewGroup parent) {
570ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (convertView == null) {
571ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                convertView = createTabView((ActionBar.Tab) getItem(position), true);
572ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            } else {
573ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position));
574ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
575ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return convertView;
576ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
577bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
578bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
579ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private class TabClickListener implements OnClickListener {
5802c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        TabClickListener() {
5812c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        }
5822c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas
583dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas        @Override
584ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public void onClick(View view) {
585ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            TabView tabView = (TabView) view;
586ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            tabView.getTab().select();
587ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final int tabCount = mTabLayout.getChildCount();
588ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            for (int i = 0; i < tabCount; i++) {
589ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final View child = mTabLayout.getChildAt(i);
590ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                child.setSelected(child == view);
591ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
592ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
593bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
594bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
59549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    protected class VisibilityAnimListener implements ViewPropertyAnimatorListener {
59649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private boolean mCanceled = false;
59749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private int mFinalVisibility;
59849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
59949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public VisibilityAnimListener withFinalVisibility(ViewPropertyAnimatorCompat animation,
60049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                int visibility) {
60149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mFinalVisibility = visibility;
60249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mVisibilityAnim = animation;
60349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return this;
60449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
60549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
60649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
60749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void onAnimationStart(View view) {
60849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            setVisibility(VISIBLE);
60949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mCanceled = false;
61049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
61149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
61249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
61349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void onAnimationEnd(View view) {
61449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (mCanceled) return;
61549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
61649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mVisibilityAnim = null;
61749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            setVisibility(mFinalVisibility);
61849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
61949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
62049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
62149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void onAnimationCancel(View view) {
62249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mCanceled = true;
62349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
62449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
625bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell}
626ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
627