QSIconViewImpl.java revision 9a82d124628350e64a835043baffced59ffcd143
1dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk/*
2702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk * Copyright (C) 2017 The Android Open Source Project
3dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk *
4702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk * except in compliance with the License. You may obtain a copy of the License at
6dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk *
7dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
8dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk *
9702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
10702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk * KIND, either express or implied. See the License for the specific language governing
12702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk * permissions and limitations under the License.
13dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk */
14dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
15702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkpackage com.android.systemui.qs.tileimpl;
16dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
17702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkimport static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
183250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
193250885c9feb9b42d60058a823c57a027c0dcf58Jason Monkimport android.animation.ValueAnimator;
20dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.content.Context;
213250885c9feb9b42d60058a823c57a027c0dcf58Jason Monkimport android.content.res.ColorStateList;
22dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.content.res.Resources;
233250885c9feb9b42d60058a823c57a027c0dcf58Jason Monkimport android.graphics.Color;
24dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.graphics.drawable.Animatable;
25dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.graphics.drawable.Drawable;
26dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.view.View;
27dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.widget.ImageView;
28eae7c318864bcfd814c8be697315f829952ccc69Jason Monkimport android.widget.ImageView.ScaleType;
293250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
30dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport com.android.systemui.R;
31702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkimport com.android.systemui.plugins.qs.QSIconView;
32702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkimport com.android.systemui.plugins.qs.QSTile;
33e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monkimport com.android.systemui.plugins.qs.QSTile.State;
34dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
35dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport java.util.Objects;
36dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
37702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkpublic class QSIconViewImpl extends QSIconView {
38dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
392f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen    protected final View mIcon;
402f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen    protected final int mIconSizePx;
412f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen    protected final int mTilePaddingBelowIconPx;
421aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk    private boolean mAnimationEnabled = true;
433250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk    private int mState = -1;
443250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk    private int mTint;
45dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
46702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk    public QSIconViewImpl(Context context) {
47dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        super(context);
48dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
49dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        final Resources res = context.getResources();
50dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        mIconSizePx = res.getDimensionPixelSize(R.dimen.qs_tile_icon_size);
51dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        mTilePaddingBelowIconPx =  res.getDimensionPixelSize(R.dimen.qs_tile_padding_below_icon);
52dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
53dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        mIcon = createIcon();
54dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        addView(mIcon);
55dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
56dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
571aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk    public void disableAnimation() {
581aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk        mAnimationEnabled = false;
591aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk    }
601aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk
612f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen    public View getIconView() {
622f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen        return mIcon;
632f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen    }
642f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen
65dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    @Override
66dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
67dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        final int w = MeasureSpec.getSize(widthMeasureSpec);
68dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        final int iconSpec = exactly(mIconSizePx);
69dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        mIcon.measure(MeasureSpec.makeMeasureSpec(w, getIconMeasureMode()), iconSpec);
70dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        setMeasuredDimension(w, mIcon.getMeasuredHeight() + mTilePaddingBelowIconPx);
71dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
72dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
73dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    @Override
74dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    protected void onLayout(boolean changed, int l, int t, int r, int b) {
75dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        final int w = getMeasuredWidth();
76dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        int top = 0;
77dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
78dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        layout(mIcon, iconLeft, top);
79dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
80dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
81dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    public void setIcon(QSTile.State state) {
82dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        setIcon((ImageView) mIcon, state);
83dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
84dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
85e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk    protected void updateIcon(ImageView iv, State state) {
86dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
87da9395e681bfaa21692bcb4a7a249b1d7ff2e2d3Jason Monk            boolean shouldAnimate = iv.isShown() && mAnimationEnabled
88da9395e681bfaa21692bcb4a7a249b1d7ff2e2d3Jason Monk                    && iv.getDrawable() != null;
891aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk            Drawable d = state.icon != null
90da9395e681bfaa21692bcb4a7a249b1d7ff2e2d3Jason Monk                    ? shouldAnimate ? state.icon.getDrawable(mContext)
911aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk                    : state.icon.getInvisibleDrawable(mContext) : null;
92e19cc141c388c7190a1582f0ee72c9ba67569a2dJason Monk            int padding = state.icon != null ? state.icon.getPadding() : 0;
93702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk            if (d != null) {
94d686e9c26e84e56810fcf87f6002ba8ba2b3f0c5Jason Monk                d.setAutoMirrored(false);
95dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk            }
96dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk            iv.setImageDrawable(d);
97dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk            iv.setTag(R.id.qs_icon_tag, state.icon);
98b53b6c566f8e4754406cd1c3fddfa16a27515a7eJason Monk            iv.setPadding(0, padding, 0, padding);
991aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk            if (d instanceof Animatable && iv.isShown()) {
100dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk                Animatable a = (Animatable) d;
10166239fbdfce1586555b339854b8a21f8187e805fJason Monk                a.start();
10266239fbdfce1586555b339854b8a21f8187e805fJason Monk                if (!iv.isShown()) {
103dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk                    a.stop(); // skip directly to end state
104dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk                }
105dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk            }
106dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        }
107e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk    }
108e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk
109e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk    protected void setIcon(ImageView iv, QSTile.State state) {
110e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk        updateIcon(iv, state);
1111c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        if (state.disabledByPolicy) {
1121c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
1131c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        } else {
1141c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            iv.clearColorFilter();
1151c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        }
1163250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        if (state.state != mState) {
117e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            int color = getColor(state.state);
1183250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk            mState = state.state;
1199a82d124628350e64a835043baffced59ffcd143Jason Monk            if (iv.isShown() && mTint != 0) {
1203250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk                animateGrayScale(mTint, color, iv);
1213250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk                mTint = color;
1223250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk            } else {
1233250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk                setTint(iv, color);
1243250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk                mTint = color;
1253250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk            }
1263250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        }
1273250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk    }
1283250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
129e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk    protected int getColor(int state) {
130e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk        return getColorForState(getContext(), state);
131e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk    }
132e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk
1333250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk    public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
1343250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        final float fromAlpha = Color.alpha(fromColor);
1353250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        final float toAlpha = Color.alpha(toColor);
1363250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        final float fromChannel = Color.red(fromColor);
1373250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        final float toChannel = Color.red(toColor);
1383250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
1393250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
1403250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        anim.setDuration(350);
1413250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
1423250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        anim.addUpdateListener(animation -> {
1433250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk            float fraction = animation.getAnimatedFraction();
1443250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk            int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction);
1453250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk            int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction);
1463250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
1473250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk            setTint(iv, Color.argb(alpha, channel, channel, channel));
1483250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        });
1493250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        anim.start();
150dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
151dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
1523250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk    public static void setTint(ImageView iv, int color) {
1533250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk        iv.setImageTintList(ColorStateList.valueOf(color));
1543250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk    }
1553250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
1563250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk
157dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    protected int getIconMeasureMode() {
158dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        return MeasureSpec.EXACTLY;
159dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
160dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
161dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    protected View createIcon() {
162dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        final ImageView icon = new ImageView(mContext);
163dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        icon.setId(android.R.id.icon);
164eae7c318864bcfd814c8be697315f829952ccc69Jason Monk        icon.setScaleType(ScaleType.FIT_CENTER);
165dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        return icon;
166dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
167dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
1682f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen    protected final int exactly(int size) {
169dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
170dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
171dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk
1722f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen    protected final void layout(View child, int left, int top) {
173dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
174dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk    }
175dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk}
176