QSTileView.java revision ece4a834e8ae6d7e7cf09cd3134a2acd8f8427bd
1af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock/*
2af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * Copyright (C) 2014 The Android Open Source Project
3af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock *
4af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
5af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * you may not use this file except in compliance with the License.
6af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * You may obtain a copy of the License at
7af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock *
8af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
9af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock *
10af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * Unless required by applicable law or agreed to in writing, software
11af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
12af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * See the License for the specific language governing permissions and
14af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock * limitations under the License.
15af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock */
16af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
17af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockpackage com.android.systemui.qs;
18af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
19af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.content.Context;
20af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.content.res.Resources;
21af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.content.res.TypedArray;
22af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.graphics.Typeface;
23af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.graphics.drawable.Drawable;
244bf31983d247a76142937c01bc2800b7f98d0281John Spurlockimport android.graphics.drawable.RippleDrawable;
25af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.os.Handler;
26af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.os.Looper;
27af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.os.Message;
28af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.util.TypedValue;
29af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.view.Gravity;
30af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.view.View;
31af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.view.ViewGroup;
3283e2848c562bf951fd49d85da338eb6dc459cff2John Spurlockimport android.widget.ImageView;
33af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.widget.ImageView.ScaleType;
34af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport android.widget.TextView;
35af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
36af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport com.android.systemui.R;
37af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport com.android.systemui.qs.QSTile.State;
38af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
39af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock/** View that represents a standard quick settings tile. **/
40af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockpublic class QSTileView extends ViewGroup {
41af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
42af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            Typeface.NORMAL);
43af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
44af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    protected final Context mContext;
45af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private final View mIcon;
46af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private final View mDivider;
47af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private final H mHandler = new H();
484bf31983d247a76142937c01bc2800b7f98d0281John Spurlock    private final int mIconSizePx;
4992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock    private final int mTileSpacingPx;
5092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock    private final int mTilePaddingTopPx;
5192d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock    private final int mTilePaddingBelowIconPx;
5239076ed379c293399292d1c6b799866c1321b44bJohn Spurlock    private final int mDualTileVerticalPaddingPx;
53e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek    private final View mTopBackgroundView;
54af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
55d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock    private TextView mLabel;
5692d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock    private QSDualTileLabel mDualLabel;
57af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private boolean mDual;
58af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private OnClickListener mClickPrimary;
59af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private OnClickListener mClickSecondary;
604bf31983d247a76142937c01bc2800b7f98d0281John Spurlock    private RippleDrawable mRipple;
61af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
62af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    public QSTileView(Context context) {
63af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        super(context);
64af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
65af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mContext = context;
66af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        final Resources res = context.getResources();
674bf31983d247a76142937c01bc2800b7f98d0281John Spurlock        mIconSizePx = res.getDimensionPixelSize(R.dimen.qs_tile_icon_size);
6892d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        mTileSpacingPx = res.getDimensionPixelSize(R.dimen.qs_tile_spacing);
6992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        mTilePaddingTopPx = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
7092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        mTilePaddingBelowIconPx =  res.getDimensionPixelSize(R.dimen.qs_tile_padding_below_icon);
7139076ed379c293399292d1c6b799866c1321b44bJohn Spurlock        mDualTileVerticalPaddingPx =
7239076ed379c293399292d1c6b799866c1321b44bJohn Spurlock                res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
73d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        recreateLabel();
74af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        setClipChildren(false);
75af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
76e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        mTopBackgroundView = new View(context);
77e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        addView(mTopBackgroundView);
78e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek
79af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mIcon = createIcon();
80af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        addView(mIcon);
81af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
82af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mDivider = new View(mContext);
834bf31983d247a76142937c01bc2800b7f98d0281John Spurlock        mDivider.setBackgroundColor(res.getColor(R.color.qs_tile_divider));
844bf31983d247a76142937c01bc2800b7f98d0281John Spurlock        final int dh = res.getDimensionPixelSize(R.dimen.qs_tile_divider_height);
85af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mDivider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dh));
86af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        addView(mDivider);
87af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
88af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        setClickable(true);
89af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
90af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
91d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock    private void recreateLabel() {
92d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        CharSequence labelText = null;
93e5557a972ca190cb82026a5dd0c53f4d119fa05aSelim Cinek        CharSequence labelDescription = null;
94d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        if (mLabel != null) {
95d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock            labelText = mLabel.getText();
96d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock            removeView(mLabel);
9792d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel = null;
9892d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        }
9992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        if (mDualLabel != null) {
10092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            labelText = mDualLabel.getText();
101e5557a972ca190cb82026a5dd0c53f4d119fa05aSelim Cinek            labelDescription = mLabel.getContentDescription();
10292d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            removeView(mDualLabel);
10392d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel = null;
104d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        }
105d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        final Resources res = mContext.getResources();
10692d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        if (mDual) {
10739076ed379c293399292d1c6b799866c1321b44bJohn Spurlock            mDualLabel = new QSDualTileLabel(mContext);
10892d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel.setId(android.R.id.title);
10939076ed379c293399292d1c6b799866c1321b44bJohn Spurlock            mDualLabel.setBackgroundResource(R.drawable.btn_borderless_rect);
11092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel.setTextColor(res.getColor(R.color.qs_tile_text));
11139076ed379c293399292d1c6b799866c1321b44bJohn Spurlock            mDualLabel.setPadding(0, mDualTileVerticalPaddingPx, 0, mDualTileVerticalPaddingPx);
11292d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel.setTypeface(CONDENSED);
11392d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
11492d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock                    res.getDimensionPixelSize(R.dimen.qs_tile_text_size));
11592d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel.setClickable(true);
11692d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel.setOnClickListener(mClickSecondary);
117e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            mDualLabel.setFocusable(true);
11892d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            if (labelText != null) {
11992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock                mDualLabel.setText(labelText);
12092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            }
121e5557a972ca190cb82026a5dd0c53f4d119fa05aSelim Cinek            if (labelDescription != null) {
122e5557a972ca190cb82026a5dd0c53f4d119fa05aSelim Cinek                mDualLabel.setContentDescription(labelDescription);
123e5557a972ca190cb82026a5dd0c53f4d119fa05aSelim Cinek            }
12492d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            addView(mDualLabel);
12592d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        } else {
12692d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel = new TextView(mContext);
12792d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setId(android.R.id.title);
12892d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setTextColor(res.getColor(R.color.qs_tile_text));
12992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setGravity(Gravity.CENTER_HORIZONTAL);
13092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setMinLines(2);
13192d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setPadding(0, 0, 0, 0);
13292d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setTypeface(CONDENSED);
13392d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
13492d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock                    res.getDimensionPixelSize(R.dimen.qs_tile_text_size));
13592d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setClickable(false);
13692d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            if (labelText != null) {
13792d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock                mLabel.setText(labelText);
13892d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            }
13992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            addView(mLabel);
140d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        }
141d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock    }
142d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock
143af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    public void setDual(boolean dual) {
144d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        final boolean changed = dual != mDual;
145af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mDual = dual;
146d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        if (changed) {
147d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock            recreateLabel();
148d47a3f3bbe5264061bf0c506976efafa0d0f2957John Spurlock        }
149e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        Drawable tileBackground = getTileBackground();
150e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        if (tileBackground instanceof RippleDrawable) {
151e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            setRipple((RippleDrawable) tileBackground);
152e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        }
153e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        if (dual) {
154e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            mTopBackgroundView.setOnClickListener(mClickPrimary);
155e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            setOnClickListener(null);
156e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            setClickable(false);
157e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
158e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            mTopBackgroundView.setBackground(tileBackground);
159e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        } else {
160e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            mTopBackgroundView.setOnClickListener(null);
161e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            mTopBackgroundView.setClickable(false);
162e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            setOnClickListener(mClickPrimary);
163e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
164e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            setBackground(tileBackground);
165e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        }
166e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        mTopBackgroundView.setFocusable(dual);
167e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        setFocusable(!dual);
168af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mDivider.setVisibility(dual ? VISIBLE : GONE);
169af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        postInvalidate();
170af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
171af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
172e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek    private void setRipple(RippleDrawable tileBackground) {
173e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        mRipple = tileBackground;
174e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        if (getWidth() != 0) {
175e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            updateRippleSize(getWidth(), getHeight());
176e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        }
177e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek    }
178e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek
179af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    public void init(OnClickListener clickPrimary, OnClickListener clickSecondary) {
180af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mClickPrimary = clickPrimary;
181af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mClickSecondary = clickSecondary;
182af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
183af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
184af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    protected View createIcon() {
18583e2848c562bf951fd49d85da338eb6dc459cff2John Spurlock        final ImageView icon = new ImageView(mContext);
186af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        icon.setId(android.R.id.icon);
187af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        icon.setScaleType(ScaleType.CENTER_INSIDE);
188af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        return icon;
189af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
190af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
1914bf31983d247a76142937c01bc2800b7f98d0281John Spurlock    private Drawable getTileBackground() {
192856edebad73560e9b1cce021a7de9a0470d07176John Spurlock        final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless };
193af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        final TypedArray ta = mContext.obtainStyledAttributes(attrs);
194af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        final Drawable d = ta.getDrawable(0);
195af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        ta.recycle();
196af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        return d;
197af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
198af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
19992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock    private View labelView() {
20092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        return mDual ? mDualLabel : mLabel;
20192d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock    }
20292d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock
203af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    @Override
204af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
205af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        final int w = MeasureSpec.getSize(widthMeasureSpec);
206af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        final int h = MeasureSpec.getSize(heightMeasureSpec);
2074bf31983d247a76142937c01bc2800b7f98d0281John Spurlock        final int iconSpec = exactly(mIconSizePx);
208af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mIcon.measure(iconSpec, iconSpec);
20992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        labelView().measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
210af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        if (mDual) {
211af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
212af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        }
213e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        int heightSpec = exactly(
214e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek                mIconSizePx + mTilePaddingBelowIconPx + mTilePaddingTopPx);
215e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        mTopBackgroundView.measure(widthMeasureSpec, heightSpec);
216af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        setMeasuredDimension(w, h);
217af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
218af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
219af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private static int exactly(int size) {
220af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
221af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
222af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
223af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    @Override
224af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    protected void onLayout(boolean changed, int l, int t, int r, int b) {
225af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        final int w = getMeasuredWidth();
226529aa73af20204c21694fbeac9799eaa79f664f8John Spurlock        final int h = getMeasuredHeight();
227af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
228e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        layout(mTopBackgroundView, 0, mTileSpacingPx);
229e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek
23092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        int top = 0;
23192d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        top += mTileSpacingPx;
23292d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        top += mTilePaddingTopPx;
233af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
234af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        layout(mIcon, iconLeft, top);
2354bf31983d247a76142937c01bc2800b7f98d0281John Spurlock        if (mRipple != null) {
236e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek            updateRippleSize(w, h);
237e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek
2384bf31983d247a76142937c01bc2800b7f98d0281John Spurlock        }
239af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        top = mIcon.getBottom();
24092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        top += mTilePaddingBelowIconPx;
241af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        if (mDual) {
242af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            layout(mDivider, 0, top);
243af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            top = mDivider.getBottom();
244af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        }
24592d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        layout(labelView(), 0, top);
246af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
247af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
248e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek    private void updateRippleSize(int width, int height) {
249e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        // center the touch feedback on the center of the icon, and dial it down a bit
250e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        final int cx = width / 2;
251e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        final int cy = mDual ? mIcon.getTop() + mIcon.getHeight() / 2 : height / 2;
252e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        final int rad = (int)(mIcon.getHeight() * 1.25f);
253e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek        mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
254e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek    }
255e32010ac6120278fea41e49b9832af79b1b5463eSelim Cinek
256af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private static void layout(View child, int left, int top) {
257af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
258af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
259af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
260af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    protected void handleStateChanged(QSTile.State state) {
26183e2848c562bf951fd49d85da338eb6dc459cff2John Spurlock        if (mIcon instanceof ImageView) {
26283e2848c562bf951fd49d85da338eb6dc459cff2John Spurlock            ImageView iv = (ImageView) mIcon;
263af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            if (state.icon != null) {
26483e2848c562bf951fd49d85da338eb6dc459cff2John Spurlock                iv.setImageDrawable(state.icon);
265af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            } else if (state.iconId > 0) {
26683e2848c562bf951fd49d85da338eb6dc459cff2John Spurlock                iv.setImageResource(state.iconId);
267af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            }
268af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        }
26992d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        if (mDual) {
27092d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mDualLabel.setText(state.label);
271e5557a972ca190cb82026a5dd0c53f4d119fa05aSelim Cinek            mDualLabel.setContentDescription(state.dualLabelContentDescription);
27292d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        } else {
27392d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock            mLabel.setText(state.label);
27492d9b19e1bc5f93ef31c4e6eb3395eaf78a5c84eJohn Spurlock        }
275af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        setContentDescription(state.contentDescription);
276af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
277af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
278af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    public void onStateChanged(QSTile.State state) {
279af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
280af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
281af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock
282af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    private class H extends Handler {
283af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        private static final int STATE_CHANGED = 1;
284af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        public H() {
285af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            super(Looper.getMainLooper());
286af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        }
287af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        @Override
288af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        public void handleMessage(Message msg) {
289af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            if (msg.what == STATE_CHANGED) {
290af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock                handleStateChanged((State) msg.obj);
291af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock            }
292af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock        }
293af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock    }
294ece4a834e8ae6d7e7cf09cd3134a2acd8f8427bdSelim Cinek}
295