13bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu/*
23bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * Copyright (C) 2017 The Android Open Source Project
33bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu *
43bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * Licensed under the Apache License, Version 2.0 (the "License");
53bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * you may not use this file except in compliance with the License.
63bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * You may obtain a copy of the License at
73bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu *
83bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu *      http://www.apache.org/licenses/LICENSE-2.0
93bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu *
103bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * Unless required by applicable law or agreed to in writing, software
113bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * distributed under the License is distributed on an "AS IS" BASIS,
123bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * See the License for the specific language governing permissions and
143bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * limitations under the License.
153bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu */
16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.widget;
173bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
18ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
193bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
203bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.content.Context;
213bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.graphics.Bitmap;
223bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.util.AttributeSet;
233bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.util.SparseArray;
243bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.view.View;
253bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.view.ViewGroup;
263bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.widget.ImageView;
273bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.widget.LinearLayout;
283bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
298619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.annotation.RestrictTo;
308619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.leanback.R;
318619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas
323bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu/**
333bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * @hide
343bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu */
353bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu@RestrictTo(LIBRARY_GROUP)
363bcad88cbf4488e747d84893c35f2351b8f84afeDake Gupublic class ThumbsBar extends LinearLayout {
373bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
38e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    // initial value for Thumb's number before measuring the screen size
39e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    int mNumOfThumbs = -1;
40e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    int mThumbWidthInPixel;
41e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    int mThumbHeightInPixel;
42e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    int mHeroThumbWidthInPixel;
43e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    int mHeroThumbHeightInPixel;
44e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    int mMeasuredMarginInPixel;
453bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    final SparseArray<Bitmap> mBitmaps = new SparseArray<>();
463bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
47e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    // flag to determine if the number of thumbs in thumbs bar is set by user through
48e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    // setNumberofThumbs API or auto-calculated according to android tv design spec.
49e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    private boolean mIsUserSets = false;
50e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli
513bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public ThumbsBar(Context context, AttributeSet attrs) {
523bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        this(context, attrs, 0);
533bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
543bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
553bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public ThumbsBar(Context context, AttributeSet attrs, int defStyle) {
563bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        super(context, attrs, defStyle);
57e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        // According to the spec,
58e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        // the width of non-hero thumb should be 80% of HeroThumb's Width, i.e. 0.8 * 192dp = 154dp
59e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mThumbWidthInPixel = context.getResources().getDimensionPixelSize(
60e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                R.dimen.lb_playback_transport_thumbs_width);
61e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mThumbHeightInPixel = context.getResources().getDimensionPixelSize(
62e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                R.dimen.lb_playback_transport_thumbs_height);
63e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        // According to the spec, the width of HeroThumb should be 192dp
64e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mHeroThumbHeightInPixel = context.getResources().getDimensionPixelSize(
65e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                R.dimen.lb_playback_transport_hero_thumbs_width);
66e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mHeroThumbWidthInPixel = context.getResources().getDimensionPixelSize(
67e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                R.dimen.lb_playback_transport_hero_thumbs_height);
68e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        // According to the spec, the margin between thumbs to be 4dp
69e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mMeasuredMarginInPixel = context.getResources().getDimensionPixelSize(
70e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                R.dimen.lb_playback_transport_thumbs_margin);
713bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
723bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
733bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
743bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     * Get hero index which is the middle child.
753bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
763bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public int getHeroIndex() {
773bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        return getChildCount() / 2;
783bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
793bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
803bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
813bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     * Set size of thumb view in pixels
823bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
833bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public void setThumbSize(int width, int height) {
84e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mThumbHeightInPixel = height;
85e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mThumbWidthInPixel = width;
863bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int heroIndex = getHeroIndex();
873bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        for (int i = 0; i < getChildCount(); i++) {
883bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            if (heroIndex != i) {
893bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                View child = getChildAt(i);
903bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
913bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                boolean changed = false;
923bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (lp.height != height) {
933bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    lp.height = height;
943bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    changed = true;
953bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
963bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (lp.width != width) {
973bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    lp.width = width;
983bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    changed = true;
993bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
1003bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (changed) {
1013bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    child.setLayoutParams(lp);
1023bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
1033bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            }
1043bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
1053bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
1063bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
1073bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
1083bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     * Set size of hero thumb view in pixels, it is usually larger than other thumbs.
1093bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
1103bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public void setHeroThumbSize(int width, int height) {
111e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mHeroThumbHeightInPixel = height;
112e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mHeroThumbWidthInPixel = width;
1133bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int heroIndex = getHeroIndex();
1143bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        for (int i = 0; i < getChildCount(); i++) {
1153bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            if (heroIndex == i) {
1163bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                View child = getChildAt(i);
1173bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
1183bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                boolean changed = false;
1193bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (lp.height != height) {
1203bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    lp.height = height;
1213bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    changed = true;
1223bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
1233bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (lp.width != width) {
1243bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    lp.width = width;
1253bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    changed = true;
1263bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
1273bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (changed) {
1283bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    child.setLayoutParams(lp);
1293bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
1303bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            }
1313bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
1323bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
1333bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
1343bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
135e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * Set the space between thumbs in pixels
136e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     */
137e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    public void setThumbSpace(int spaceInPixel) {
138e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mMeasuredMarginInPixel = spaceInPixel;
139e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        requestLayout();
140e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    }
141e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli
142e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    /**
143e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * Set number of thumb views.
1443bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
1453bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public void setNumberOfThumbs(int numOfThumbs) {
146e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        mIsUserSets = true;
1473bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mNumOfThumbs = numOfThumbs;
148e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        setNumberOfThumbsInternal();
149e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    }
150e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli
151e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    /**
152e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * Helper function for setNumberOfThumbs.
153e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * Will Update the layout settings in ThumbsBar based on mNumOfThumbs
154e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     */
155e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    private void setNumberOfThumbsInternal() {
1563bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        while (getChildCount() > mNumOfThumbs) {
1573bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            removeView(getChildAt(getChildCount() - 1));
1583bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
1593bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        while (getChildCount() < mNumOfThumbs) {
1603bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            View view = createThumbView(this);
161e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(mThumbWidthInPixel,
162e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                    mThumbHeightInPixel);
1633bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            addView(view, lp);
1643bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
1653bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int heroIndex = getHeroIndex();
1663bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        for (int i = 0; i < getChildCount(); i++) {
1673bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            View child = getChildAt(i);
1683bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
1693bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            if (heroIndex == i) {
170e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                lp.width = mHeroThumbWidthInPixel;
171e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                lp.height = mHeroThumbHeightInPixel;
1723bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            } else {
173e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                lp.width = mThumbWidthInPixel;
174e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                lp.height = mThumbHeightInPixel;
1753bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            }
1763bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            child.setLayoutParams(lp);
1773bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
1783bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
1793bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
1806c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu    private static int roundUp(int num, int divisor) {
1816c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu        return (num + divisor - 1) / divisor;
1826c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu    }
1836c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu
184e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    /**
185e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * Helper function to compute how many thumbs should be put in the screen
186e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * Assume we should put x's non-hero thumbs in the screen, the equation should be
187e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     *   192dp (width of hero thumbs) +
188e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     *   154dp (width of common thumbs) * x +
189e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     *   4dp (width of the margin between thumbs) * x
190e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     *     = width
191e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * So the calculated number of non-hero thumbs should be (width - 192dp) / 158dp.
192e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * If the calculated number of non-hero thumbs is less than 2, it will be updated to 2
193e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * or if the calculated number or non-hero thumbs is not an even number, it will be
194e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * decremented by one.
195e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * This processing is used to make sure the arrangement of non-hero thumbs
196e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * in ThumbsBar is symmetrical.
197e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * Also there should be a hero thumb in the middle of the ThumbsBar,
198e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * the final result should be non-hero thumbs (after processing) + 1.
199e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     *
200e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * @param  widthInPixel measured width in pixel
201e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     * @return The number of thumbs
202e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli     */
203e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    private int calculateNumOfThumbs(int widthInPixel) {
2046c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu        int nonHeroThumbNum = roundUp(widthInPixel - mHeroThumbWidthInPixel,
2056c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu                mThumbWidthInPixel + mMeasuredMarginInPixel);
206e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        if (nonHeroThumbNum < 2) {
207e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            // If the calculated number of non-hero thumbs is less than 2,
208e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            // it will be updated to 2
209e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            nonHeroThumbNum = 2;
210e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        } else if ((nonHeroThumbNum & 1) != 0) {
211e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            // If the calculated number or non-hero thumbs is not an even number,
2126c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu            // it will be increased by one.
2136c41fe6074ffc9d1b472032e5356a7b5e146dc83Dake Gu            nonHeroThumbNum++;
214e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        }
215e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        // Count Hero Thumb to the final result
216e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        return nonHeroThumbNum + 1;
217e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli    }
218e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli
2193bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    @Override
2203bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
2213bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
2223bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int width = getMeasuredWidth();
223e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        // If the number of thumbs in ThumbsBar is not set by user explicitly, it will be
224e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        // recalculated based on Android TV Design Spec
225e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli        if (!mIsUserSets) {
226e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            int numOfThumbs = calculateNumOfThumbs(width);
227e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            // Set new number of thumbs when calculation result is different with current number
228e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            if (mNumOfThumbs != numOfThumbs) {
229e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                mNumOfThumbs = numOfThumbs;
230e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli                setNumberOfThumbsInternal();
2313bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            }
2323bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
2333bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
2343bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2353bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    @Override
2363bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    protected void onLayout(boolean changed, int l, int t, int r, int b) {
2373bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        super.onLayout(changed, l, t, r, b);
2383bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int heroIndex = getHeroIndex();
2393bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        View heroView = getChildAt(heroIndex);
2403bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int heroLeft = getWidth() / 2 - heroView.getMeasuredWidth() / 2;
2413bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int heroRight = getWidth() / 2 + heroView.getMeasuredWidth() / 2;
2423bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        heroView.layout(heroLeft, getPaddingTop(), heroRight,
2433bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                getPaddingTop() + heroView.getMeasuredHeight());
2443bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        int heroCenter = getPaddingTop() + heroView.getMeasuredHeight() / 2;
2453bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2463bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        for (int i = heroIndex - 1; i >= 0; i--) {
247e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            heroLeft -= mMeasuredMarginInPixel;
2483bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            View child = getChildAt(i);
2493bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            child.layout(heroLeft - child.getMeasuredWidth(),
2503bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    heroCenter - child.getMeasuredHeight() / 2,
2513bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    heroLeft,
2523bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    heroCenter + child.getMeasuredHeight() / 2);
2533bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            heroLeft -= child.getMeasuredWidth();
2543bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
2553bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        for (int i = heroIndex + 1; i < mNumOfThumbs; i++) {
256e4662073e39ea860efbe9dfe4766e46b2945aee7jingjiangli            heroRight += mMeasuredMarginInPixel;
2573bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            View child = getChildAt(i);
2583bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            child.layout(heroRight,
2593bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    heroCenter - child.getMeasuredHeight() / 2,
2603bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    heroRight + child.getMeasuredWidth(),
2613bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    heroCenter + child.getMeasuredHeight() / 2);
2623bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            heroRight += child.getMeasuredWidth();
2633bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
2643bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
2653bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2663bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
2673bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     * Create a thumb view, it's by default a ImageView.
2683bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
2693bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    protected View createThumbView(ViewGroup parent) {
2703bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        return new ImageView(parent.getContext());
2713bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
2723bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2733bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
2743bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     * Clear all thumb bitmaps set on thumb views.
2753bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
2763bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public void clearThumbBitmaps() {
2773bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        for (int i = 0; i < getChildCount(); i++) {
2783bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            setThumbBitmap(i, null);
2793bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
2803bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mBitmaps.clear();
2813bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
2823bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2833bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2843bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
2853bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     * Get bitmap of given child index.
2863bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
2873bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public Bitmap getThumbBitmap(int index) {
2883bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        return mBitmaps.get(index);
2893bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
2903bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2913bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    /**
2923bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     * Set thumb bitmap for a given index of child.
2933bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu     */
2943bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public void setThumbBitmap(int index, Bitmap bitmap) {
2953bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mBitmaps.put(index, bitmap);
2963bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        ((ImageView) getChildAt(index)).setImageBitmap(bitmap);
2973bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
2983bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu}
299