18fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell/*
28fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Copyright (C) 2011 The Android Open Source Project
38fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell *
48fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Licensed under the Apache License, Version 2.0 (the "License");
58fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * you may not use this file except in compliance with the License.
68fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * You may obtain a copy of the License at
78fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell *
88fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell *      http://www.apache.org/licenses/LICENSE-2.0
98fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell *
108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Unless required by applicable law or agreed to in writing, software
118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * distributed under the License is distributed on an "AS IS" BASIS,
128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * See the License for the specific language governing permissions and
148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * limitations under the License.
158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */
168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellpackage android.support.v4.view;
188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.Context;
208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.res.TypedArray;
218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.database.DataSetObserver;
228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.graphics.drawable.Drawable;
238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.text.TextUtils.TruncateAt;
248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.util.AttributeSet;
258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.util.TypedValue;
2623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powellimport android.view.Gravity;
278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.ViewGroup;
288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.ViewParent;
298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.widget.TextView;
308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
315d6251c65f890a57aa9929eb6aacae2d8b917ec9Adam Powellimport java.lang.ref.WeakReference;
325d6251c65f890a57aa9929eb6aacae2d8b917ec9Adam Powell
338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell/**
348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * PagerTitleStrip is a non-interactive indicator of the current, next,
350574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * and previous pages of a {@link ViewPager}. It is intended to be used as a
368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * child view of a ViewPager widget in your XML layout.
378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Add it as a child of a ViewPager in your layout file and set its
388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * android:layout_gravity to TOP or BOTTOM to pin it to the top or bottom
398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * of the ViewPager. The title from each page is supplied by the method
408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * {@link PagerAdapter#getPageTitle(int)} in the adapter supplied to
418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * the ViewPager.
4224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell *
4324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * <p>For an interactive indicator, see {@link PagerTabStrip}.</p>
448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */
451ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powellpublic class PagerTitleStrip extends ViewGroup implements ViewPager.Decor {
468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private static final String TAG = "PagerTitleStrip";
478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    ViewPager mPager;
4924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    TextView mPrevText;
5024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    TextView mCurrText;
5124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    TextView mNextText;
528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mLastKnownCurrentPage = -1;
548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private float mLastKnownPositionOffset = -1;
558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mScaledTextSpacing;
5623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell    private int mGravity;
578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private boolean mUpdatingText;
598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private boolean mUpdatingPositions;
608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private final PageListener mPageListener = new PageListener();
628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
635d6251c65f890a57aa9929eb6aacae2d8b917ec9Adam Powell    private WeakReference<PagerAdapter> mWatchingAdapter;
645d6251c65f890a57aa9929eb6aacae2d8b917ec9Adam Powell
658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private static final int[] ATTRS = new int[] {
668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        android.R.attr.textAppearance,
67552468d2a1e3cbf74f3a6dcbb68fe079aed56cf9Adam Powell        android.R.attr.textSize,
688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        android.R.attr.textColor,
6923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        android.R.attr.gravity
708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    };
718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
721e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    private static final int[] TEXT_ATTRS = new int[] {
731e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        0x0101038c // android.R.attr.textAllCaps
741e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    };
751e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
76552468d2a1e3cbf74f3a6dcbb68fe079aed56cf9Adam Powell    private static final float SIDE_ALPHA = 0.6f;
778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private static final int TEXT_SPACING = 16; // dip
788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
79552468d2a1e3cbf74f3a6dcbb68fe079aed56cf9Adam Powell    private int mNonPrimaryAlpha;
8024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    int mTextColor;
81a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
821e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    interface PagerTitleStripImpl {
831e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        void setSingleLineAllCaps(TextView text);
841e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    }
851e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
861e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    static class PagerTitleStripImplBase implements PagerTitleStripImpl {
871e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        public void setSingleLineAllCaps(TextView text) {
881e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            text.setSingleLine();
891e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        }
901e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    }
911e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
921e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    static class PagerTitleStripImplIcs implements PagerTitleStripImpl {
931e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        public void setSingleLineAllCaps(TextView text) {
941e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            PagerTitleStripIcs.setSingleLineAllCaps(text);
951e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        }
961e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    }
971e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
981e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    private static final PagerTitleStripImpl IMPL;
991e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    static {
1001e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        if (android.os.Build.VERSION.SDK_INT >= 14) {
1011e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            IMPL = new PagerTitleStripImplIcs();
1021e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        } else {
1031e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            IMPL = new PagerTitleStripImplBase();
1041e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        }
1051e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    }
1061e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
1071e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    private static void setSingleLineAllCaps(TextView text) {
1081e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        IMPL.setSingleLineAllCaps(text);
1091e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    }
1101e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
1118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public PagerTitleStrip(Context context) {
1128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        this(context, null);
1138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
1148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public PagerTitleStrip(Context context, AttributeSet attrs) {
1168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        super(context, attrs);
1178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        addView(mPrevText = new TextView(context));
1198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        addView(mCurrText = new TextView(context));
1208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        addView(mNextText = new TextView(context));
1218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
1238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int textAppearance = a.getResourceId(0, 0);
1248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (textAppearance != 0) {
1258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mPrevText.setTextAppearance(context, textAppearance);
1268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mCurrText.setTextAppearance(context, textAppearance);
1278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mNextText.setTextAppearance(context, textAppearance);
1288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
12923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int textSize = a.getDimensionPixelSize(1, 0);
13023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        if (textSize != 0) {
13123b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell            setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
13223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        }
13323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        if (a.hasValue(2)) {
134552468d2a1e3cbf74f3a6dcbb68fe079aed56cf9Adam Powell            final int textColor = a.getColor(2, 0);
1358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mPrevText.setTextColor(textColor);
1368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mCurrText.setTextColor(textColor);
1378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mNextText.setTextColor(textColor);
1388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
13923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        mGravity = a.getInteger(3, Gravity.BOTTOM);
1408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        a.recycle();
1418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mTextColor = mCurrText.getTextColors().getDefaultColor();
143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        setNonPrimaryAlpha(SIDE_ALPHA);
1448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mPrevText.setEllipsize(TruncateAt.END);
1468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCurrText.setEllipsize(TruncateAt.END);
1478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mNextText.setEllipsize(TruncateAt.END);
1481e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
1491e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        boolean allCaps = false;
1501e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        if (textAppearance != 0) {
1511e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            final TypedArray ta = context.obtainStyledAttributes(textAppearance, TEXT_ATTRS);
1521e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            allCaps = ta.getBoolean(0, false);
1531e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            ta.recycle();
1541e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        }
1551e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
1561e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        if (allCaps) {
1571e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            setSingleLineAllCaps(mPrevText);
1581e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            setSingleLineAllCaps(mCurrText);
1591e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            setSingleLineAllCaps(mNextText);
1601e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        } else {
1611e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            mPrevText.setSingleLine();
1621e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            mCurrText.setSingleLine();
1631e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            mNextText.setSingleLine();
1641e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        }
1658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final float density = context.getResources().getDisplayMetrics().density;
1678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mScaledTextSpacing = (int) (TEXT_SPACING * density);
1688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
1698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
170a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    /**
171a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * Set the required spacing between title segments.
172a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *
173a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @param spacingPixels Spacing between each title displayed in pixels
174a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     */
175a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    public void setTextSpacing(int spacingPixels) {
176a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mScaledTextSpacing = spacingPixels;
177a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        requestLayout();
178a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
179a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
180a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    /**
18124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     * @return The required spacing between title segments in pixels
18224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     */
18324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public int getTextSpacing() {
18424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        return mScaledTextSpacing;
18524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
18624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
18724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    /**
188a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * Set the alpha value used for non-primary page titles.
189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *
190a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @param alpha Opacity value in the range 0-1f
191a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     */
192a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    public void setNonPrimaryAlpha(float alpha) {
193a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mNonPrimaryAlpha = (int) (alpha * 255) & 0xFF;
194a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int transparentColor = (mNonPrimaryAlpha << 24) | (mTextColor & 0xFFFFFF);
195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mPrevText.setTextColor(transparentColor);
196a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mNextText.setTextColor(transparentColor);
197a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
198a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
199a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    /**
200a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * Set the color value used as the base color for all displayed page titles.
201a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * Alpha will be ignored for non-primary page titles. See {@link #setNonPrimaryAlpha(float)}.
202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *
203a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @param color Color hex code in 0xAARRGGBB format
204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     */
205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    public void setTextColor(int color) {
206a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mTextColor = color;
207a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mCurrText.setTextColor(color);
208a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int transparentColor = (mNonPrimaryAlpha << 24) | (mTextColor & 0xFFFFFF);
209a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mPrevText.setTextColor(transparentColor);
210a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mNextText.setTextColor(transparentColor);
211a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
212a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
213a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    /**
214a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * Set the default text size to a given unit and value.
215a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * See {@link TypedValue} for the possible dimension units.
216a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *
217a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * <p>Example: to set the text size to 14px, use
218a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * setTextSize(TypedValue.COMPLEX_UNIT_PX, 14);</p>
219a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *
220a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @param unit The desired dimension unit
221a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @param size The desired size in the given units
222a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     */
223a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    public void setTextSize(int unit, float size) {
224a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mPrevText.setTextSize(unit, size);
225a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mCurrText.setTextSize(unit, size);
226a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mNextText.setTextSize(unit, size);
227a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
228a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
22923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell    /**
23023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell     * Set the {@link Gravity} used to position text within the title strip.
23123b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell     * Only the vertical gravity component is used.
23223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell     *
23323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell     * @param gravity {@link Gravity} constant for positioning title text
23423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell     */
23523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell    public void setGravity(int gravity) {
23623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        mGravity = gravity;
23723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        requestLayout();
23823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell    }
23923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell
2408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
2418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected void onAttachedToWindow() {
2428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        super.onAttachedToWindow();
2438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final ViewParent parent = getParent();
2458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (!(parent instanceof ViewPager)) {
2468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            throw new IllegalStateException(
2478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    "PagerTitleStrip must be a direct child of a ViewPager.");
2488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
2498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final ViewPager pager = (ViewPager) parent;
2518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final PagerAdapter adapter = pager.getAdapter();
2528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        pager.setInternalPageChangeListener(mPageListener);
2548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        pager.setOnAdapterChangeListener(mPageListener);
2558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mPager = pager;
2565d6251c65f890a57aa9929eb6aacae2d8b917ec9Adam Powell        updateAdapter(mWatchingAdapter != null ? mWatchingAdapter.get() : null, adapter);
2578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
2588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
2608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected void onDetachedFromWindow() {
26182971b1050c50d3be5b2cbc285c74076e6763892Adam Powell        super.onDetachedFromWindow();
26282971b1050c50d3be5b2cbc285c74076e6763892Adam Powell        if (mPager != null) {
26382971b1050c50d3be5b2cbc285c74076e6763892Adam Powell            updateAdapter(mPager.getAdapter(), null);
26482971b1050c50d3be5b2cbc285c74076e6763892Adam Powell            mPager.setInternalPageChangeListener(null);
26582971b1050c50d3be5b2cbc285c74076e6763892Adam Powell            mPager.setOnAdapterChangeListener(null);
26682971b1050c50d3be5b2cbc285c74076e6763892Adam Powell            mPager = null;
26782971b1050c50d3be5b2cbc285c74076e6763892Adam Powell        }
2688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
2698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    void updateText(int currentItem, PagerAdapter adapter) {
2718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int itemCount = adapter != null ? adapter.getCount() : 0;
2728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mUpdatingText = true;
2738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        CharSequence text = null;
2758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (currentItem >= 1 && adapter != null) {
2768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            text = adapter.getPageTitle(currentItem - 1);
2778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
2788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mPrevText.setText(text);
2798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2808d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell        mCurrText.setText(adapter != null && currentItem < itemCount ?
2818d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                adapter.getPageTitle(currentItem) : null);
2828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        text = null;
2848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (currentItem + 1 < itemCount && adapter != null) {
2858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            text = adapter.getPageTitle(currentItem + 1);
2868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
2878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mNextText.setText(text);
2888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        // Measure everything
2908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int width = getWidth() - getPaddingLeft() - getPaddingRight();
2918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int childHeight = getHeight() - getPaddingTop() - getPaddingBottom();
2928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int childWidthSpec = MeasureSpec.makeMeasureSpec((int) (width * 0.8f),
2938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                MeasureSpec.AT_MOST);
29423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST);
2958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mPrevText.measure(childWidthSpec, childHeightSpec);
2968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCurrText.measure(childWidthSpec, childHeightSpec);
2978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mNextText.measure(childWidthSpec, childHeightSpec);
2988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mLastKnownCurrentPage = currentItem;
3008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (!mUpdatingPositions) {
3025f6568e7e269783e2668527461878cadfbe65215Adam Powell            updateTextPositions(currentItem, mLastKnownPositionOffset, false);
3038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
3048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mUpdatingText = false;
3068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
3078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
3098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public void requestLayout() {
3108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (!mUpdatingText) {
3118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            super.requestLayout();
3128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
3138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
3148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    void updateAdapter(PagerAdapter oldAdapter, PagerAdapter newAdapter) {
3168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (oldAdapter != null) {
3178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            oldAdapter.unregisterDataSetObserver(mPageListener);
3185d6251c65f890a57aa9929eb6aacae2d8b917ec9Adam Powell            mWatchingAdapter = null;
3198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
3208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (newAdapter != null) {
3218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            newAdapter.registerDataSetObserver(mPageListener);
3225d6251c65f890a57aa9929eb6aacae2d8b917ec9Adam Powell            mWatchingAdapter = new WeakReference<PagerAdapter>(newAdapter);
3238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
3248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mPager != null) {
3258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mLastKnownCurrentPage = -1;
3268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mLastKnownPositionOffset = -1;
3278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            updateText(mPager.getCurrentItem(), newAdapter);
328a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            requestLayout();
3298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
3308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
3318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3325f6568e7e269783e2668527461878cadfbe65215Adam Powell    void updateTextPositions(int position, float positionOffset, boolean force) {
3338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (position != mLastKnownCurrentPage) {
3348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            updateText(position, mPager.getAdapter());
3355f6568e7e269783e2668527461878cadfbe65215Adam Powell        } else if (!force && positionOffset == mLastKnownPositionOffset) {
3368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            return;
3378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
3388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mUpdatingPositions = true;
3408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int prevWidth = mPrevText.getMeasuredWidth();
3428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int currWidth = mCurrText.getMeasuredWidth();
3438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int nextWidth = mNextText.getMeasuredWidth();
3448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int halfCurrWidth = currWidth / 2;
3458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int stripWidth = getWidth();
34723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int stripHeight = getHeight();
3488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int paddingLeft = getPaddingLeft();
3498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int paddingRight = getPaddingRight();
3508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int paddingTop = getPaddingTop();
35123b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int paddingBottom = getPaddingBottom();
3528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int textPaddedLeft = paddingLeft + halfCurrWidth;
3538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int textPaddedRight = paddingRight + halfCurrWidth;
3548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int contentWidth = stripWidth - textPaddedLeft - textPaddedRight;
3558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        float currOffset = positionOffset + 0.5f;
3578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (currOffset > 1.f) {
3588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            currOffset -= 1.f;
3598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
3608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int currCenter = stripWidth - textPaddedRight - (int) (contentWidth * currOffset);
3618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int currLeft = currCenter - currWidth / 2;
3628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int currRight = currLeft + currWidth;
3638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
36423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int prevBaseline = mPrevText.getBaseline();
36523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int currBaseline = mCurrText.getBaseline();
36623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int nextBaseline = mNextText.getBaseline();
36723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int maxBaseline = Math.max(Math.max(prevBaseline, currBaseline), nextBaseline);
36823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int prevTopOffset = maxBaseline - prevBaseline;
36923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int currTopOffset = maxBaseline - currBaseline;
37023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int nextTopOffset = maxBaseline - nextBaseline;
37123b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int alignedPrevHeight = prevTopOffset + mPrevText.getMeasuredHeight();
37223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int alignedCurrHeight = currTopOffset + mCurrText.getMeasuredHeight();
37323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int alignedNextHeight = nextTopOffset + mNextText.getMeasuredHeight();
37423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int maxTextHeight = Math.max(Math.max(alignedPrevHeight, alignedCurrHeight),
37523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                alignedNextHeight);
37623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell
37723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int vgrav = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
37823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell
37923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        int prevTop;
38023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        int currTop;
38123b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        int nextTop;
38223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        switch (vgrav) {
38323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell            default:
38423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell            case Gravity.TOP:
38523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                prevTop = paddingTop + prevTopOffset;
38623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                currTop = paddingTop + currTopOffset;
38723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                nextTop = paddingTop + nextTopOffset;
38823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                break;
38923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell            case Gravity.CENTER_VERTICAL:
39023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                final int paddedHeight = stripHeight - paddingTop - paddingBottom;
39123b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                final int centeredTop = (paddedHeight - maxTextHeight) / 2;
39223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                prevTop = centeredTop + prevTopOffset;
39323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                currTop = centeredTop + currTopOffset;
39423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                nextTop = centeredTop + nextTopOffset;
39523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                break;
39623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell            case Gravity.BOTTOM:
39723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                final int bottomGravTop = stripHeight - paddingBottom - maxTextHeight;
39823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                prevTop = bottomGravTop + prevTopOffset;
39923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                currTop = bottomGravTop + currTopOffset;
40023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                nextTop = bottomGravTop + nextTopOffset;
40123b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                break;
40223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        }
40323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell
40423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        mCurrText.layout(currLeft, currTop, currRight,
40523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                currTop + mCurrText.getMeasuredHeight());
4068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int prevLeft = Math.min(paddingLeft, currLeft - mScaledTextSpacing - prevWidth);
40823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        mPrevText.layout(prevLeft, prevTop, prevLeft + prevWidth,
40923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                prevTop + mPrevText.getMeasuredHeight());
4108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int nextLeft = Math.max(stripWidth - paddingRight - nextWidth,
4128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                currRight + mScaledTextSpacing);
41323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        mNextText.layout(nextLeft, nextTop, nextLeft + nextWidth,
41423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                nextTop + mNextText.getMeasuredHeight());
4158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mLastKnownPositionOffset = positionOffset;
4178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mUpdatingPositions = false;
4188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
4198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
4218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
4228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
4238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
4248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
4258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
4268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (widthMode != MeasureSpec.EXACTLY) {
4288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            throw new IllegalStateException("Must measure with an exact width");
4298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
4308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int childHeight = heightSize;
4321e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        int minHeight = getMinHeight();
4338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int padding = 0;
4348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        padding = getPaddingTop() + getPaddingBottom();
4358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        childHeight -= padding;
4368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int childWidthSpec = MeasureSpec.makeMeasureSpec((int) (widthSize * 0.8f),
4388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                MeasureSpec.AT_MOST);
43923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell        final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST);
4408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mPrevText.measure(childWidthSpec, childHeightSpec);
4428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCurrText.measure(childWidthSpec, childHeightSpec);
4438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mNextText.measure(childWidthSpec, childHeightSpec);
4448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (heightMode == MeasureSpec.EXACTLY) {
4468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            setMeasuredDimension(widthSize, heightSize);
4478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        } else {
4488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            int textHeight = mCurrText.getMeasuredHeight();
4498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            setMeasuredDimension(widthSize, Math.max(minHeight, textHeight + padding));
4508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
4518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
4528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
4548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mPager != null) {
4561e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            final float offset = mLastKnownPositionOffset >= 0 ? mLastKnownPositionOffset : 0;
45740f36156156b6aedaf47e65f403212136c7cd7b9Adam Powell            updateTextPositions(mLastKnownCurrentPage, offset, true);
4581e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        }
4591e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    }
4601e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell
4611e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell    int getMinHeight() {
4621e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        int minHeight = 0;
4631e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        final Drawable bg = getBackground();
4641e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        if (bg != null) {
4651e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell            minHeight = bg.getIntrinsicHeight();
4668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
4671e37da8d4fbd23a4440f32eba784520dc7a03265Adam Powell        return minHeight;
4688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
4698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private class PageListener extends DataSetObserver implements ViewPager.OnPageChangeListener,
4718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            ViewPager.OnAdapterChangeListener {
4728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        private int mScrollState;
4738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
4758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
4768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (positionOffset > 0.5f) {
4778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                // Consider ourselves to be on the next page when we're 50% of the way there.
4788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                position++;
4798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
4805f6568e7e269783e2668527461878cadfbe65215Adam Powell            updateTextPositions(position, positionOffset, false);
4818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
4828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
4848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onPageSelected(int position) {
4858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
4868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                // Only update the text here if we're not dragging or settling.
4878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                updateText(mPager.getCurrentItem(), mPager.getAdapter());
488cc1cad0588e86d568b9467aa2669c2160af46503Adam Powell
489cc1cad0588e86d568b9467aa2669c2160af46503Adam Powell                final float offset = mLastKnownPositionOffset >= 0 ? mLastKnownPositionOffset : 0;
490cc1cad0588e86d568b9467aa2669c2160af46503Adam Powell                updateTextPositions(mPager.getCurrentItem(), offset, true);
4918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
4928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
4938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
4958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onPageScrollStateChanged(int state) {
4968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mScrollState = state;
4978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
4988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
5008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter) {
5018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            updateAdapter(oldAdapter, newAdapter);
5028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
5038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
5048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
5058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onChanged() {
5068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            updateText(mPager.getCurrentItem(), mPager.getAdapter());
507cc1cad0588e86d568b9467aa2669c2160af46503Adam Powell
508cc1cad0588e86d568b9467aa2669c2160af46503Adam Powell            final float offset = mLastKnownPositionOffset >= 0 ? mLastKnownPositionOffset : 0;
509cc1cad0588e86d568b9467aa2669c2160af46503Adam Powell            updateTextPositions(mPager.getCurrentItem(), offset, true);
5108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
5118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
5128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell}
513