blob: cdd0ebc57d5c68fe283e3d4c7e17d99dcd9b9857 [file] [log] [blame]
Jason Monkdc35dcb2015-12-04 16:36:15 -05001/*
Jason Monk702e2eb2017-03-03 16:53:44 -05002 * Copyright (C) 2017 The Android Open Source Project
Jason Monkdc35dcb2015-12-04 16:36:15 -05003 *
Jason Monk702e2eb2017-03-03 16:53:44 -05004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
Jason Monkdc35dcb2015-12-04 16:36:15 -05006 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
Jason Monk702e2eb2017-03-03 16:53:44 -05009 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
Jason Monkdc35dcb2015-12-04 16:36:15 -050013 */
14
Jason Monk702e2eb2017-03-03 16:53:44 -050015package com.android.systemui.qs.tileimpl;
Jason Monkdc35dcb2015-12-04 16:36:15 -050016
Jason Monk702e2eb2017-03-03 16:53:44 -050017import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
Jason Monk32508852017-01-18 09:17:13 -050018
19import android.animation.ValueAnimator;
Jason Monkdc35dcb2015-12-04 16:36:15 -050020import android.content.Context;
Jason Monk32508852017-01-18 09:17:13 -050021import android.content.res.ColorStateList;
Jason Monkdc35dcb2015-12-04 16:36:15 -050022import android.content.res.Resources;
Jason Monk32508852017-01-18 09:17:13 -050023import android.graphics.Color;
Jason Monke645aee2017-03-31 13:19:26 -040024import android.graphics.drawable.Animatable2;
25import android.graphics.drawable.Animatable2.AnimationCallback;
Jason Monkdc35dcb2015-12-04 16:36:15 -050026import android.graphics.drawable.Drawable;
27import android.view.View;
Jason Monkdc35dcb2015-12-04 16:36:15 -050028import android.widget.ImageView;
Jason Monkeae7c312016-02-04 13:00:48 -050029import android.widget.ImageView.ScaleType;
Jason Monk32508852017-01-18 09:17:13 -050030
Jason Monkdc35dcb2015-12-04 16:36:15 -050031import com.android.systemui.R;
Jason Monk702e2eb2017-03-03 16:53:44 -050032import com.android.systemui.plugins.qs.QSIconView;
33import com.android.systemui.plugins.qs.QSTile;
Jason Monke5b770e2017-03-03 21:49:29 -050034import com.android.systemui.plugins.qs.QSTile.State;
Jason Monkdc35dcb2015-12-04 16:36:15 -050035
36import java.util.Objects;
37
Jason Monk702e2eb2017-03-03 16:53:44 -050038public class QSIconViewImpl extends QSIconView {
Jason Monkdc35dcb2015-12-04 16:36:15 -050039
Evan Laird8d2e5402017-06-08 10:36:57 -040040 public static final long QS_ANIM_LENGTH = 350;
41
Xiaohui Chen2f3551b2016-04-07 10:37:25 -070042 protected final View mIcon;
43 protected final int mIconSizePx;
44 protected final int mTilePaddingBelowIconPx;
Jason Monk1aec93f2016-03-01 09:39:30 -050045 private boolean mAnimationEnabled = true;
Jason Monk32508852017-01-18 09:17:13 -050046 private int mState = -1;
47 private int mTint;
Jason Monkdc35dcb2015-12-04 16:36:15 -050048
Jason Monk702e2eb2017-03-03 16:53:44 -050049 public QSIconViewImpl(Context context) {
Jason Monkdc35dcb2015-12-04 16:36:15 -050050 super(context);
51
52 final Resources res = context.getResources();
53 mIconSizePx = res.getDimensionPixelSize(R.dimen.qs_tile_icon_size);
54 mTilePaddingBelowIconPx = res.getDimensionPixelSize(R.dimen.qs_tile_padding_below_icon);
55
56 mIcon = createIcon();
57 addView(mIcon);
58 }
59
Jason Monk1aec93f2016-03-01 09:39:30 -050060 public void disableAnimation() {
61 mAnimationEnabled = false;
62 }
63
Xiaohui Chen2f3551b2016-04-07 10:37:25 -070064 public View getIconView() {
65 return mIcon;
66 }
67
Jason Monkdc35dcb2015-12-04 16:36:15 -050068 @Override
69 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
70 final int w = MeasureSpec.getSize(widthMeasureSpec);
71 final int iconSpec = exactly(mIconSizePx);
72 mIcon.measure(MeasureSpec.makeMeasureSpec(w, getIconMeasureMode()), iconSpec);
73 setMeasuredDimension(w, mIcon.getMeasuredHeight() + mTilePaddingBelowIconPx);
74 }
75
76 @Override
77 protected void onLayout(boolean changed, int l, int t, int r, int b) {
78 final int w = getMeasuredWidth();
Jason Monkdc35dcb2015-12-04 16:36:15 -050079 int top = 0;
80 final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
81 layout(mIcon, iconLeft, top);
82 }
83
84 public void setIcon(QSTile.State state) {
85 setIcon((ImageView) mIcon, state);
86 }
87
Jason Monke5b770e2017-03-03 21:49:29 -050088 protected void updateIcon(ImageView iv, State state) {
Jason Monk395617f2017-05-05 14:07:58 -040089 if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))
90 || !Objects.equals(state.slash, iv.getTag(R.id.qs_slash_tag))) {
Jason Monkda9395e2017-03-27 15:18:23 -040091 boolean shouldAnimate = iv.isShown() && mAnimationEnabled
92 && iv.getDrawable() != null;
Jason Monk1aec93f2016-03-01 09:39:30 -050093 Drawable d = state.icon != null
Jason Monkda9395e2017-03-27 15:18:23 -040094 ? shouldAnimate ? state.icon.getDrawable(mContext)
Jason Monk1aec93f2016-03-01 09:39:30 -050095 : state.icon.getInvisibleDrawable(mContext) : null;
Jason Monke19cc142016-06-01 10:25:01 -040096 int padding = state.icon != null ? state.icon.getPadding() : 0;
Jason Monk702e2eb2017-03-03 16:53:44 -050097 if (d != null) {
Jason Monkd686e9c2017-03-27 15:45:32 -040098 d.setAutoMirrored(false);
Jason Monkdc35dcb2015-12-04 16:36:15 -050099 }
100 iv.setImageDrawable(d);
Jason Monk395617f2017-05-05 14:07:58 -0400101 if (state.slash != null && iv instanceof SlashImageView) {
102 ((SlashImageView) iv).setState(state.slash);
103 }
Jason Monkdc35dcb2015-12-04 16:36:15 -0500104 iv.setTag(R.id.qs_icon_tag, state.icon);
Jason Monk395617f2017-05-05 14:07:58 -0400105 iv.setTag(R.id.qs_slash_tag, state.slash);
Jason Monkb53b6c52016-02-24 17:25:49 -0500106 iv.setPadding(0, padding, 0, padding);
Jason Monke645aee2017-03-31 13:19:26 -0400107 if (d instanceof Animatable2) {
108 Animatable2 a = (Animatable2) d;
Jason Monk66239fb2015-12-21 14:27:00 -0500109 a.start();
Jason Monke645aee2017-03-31 13:19:26 -0400110 if (state.isTransient) {
111 a.registerAnimationCallback(new AnimationCallback() {
112 @Override
113 public void onAnimationEnd(Drawable drawable) {
114 a.start();
115 }
116 });
Jason Monkdc35dcb2015-12-04 16:36:15 -0500117 }
118 }
119 }
Jason Monke5b770e2017-03-03 21:49:29 -0500120 }
121
122 protected void setIcon(ImageView iv, QSTile.State state) {
123 updateIcon(iv, state);
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000124 if (state.disabledByPolicy) {
125 iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
126 } else {
127 iv.clearColorFilter();
128 }
Jason Monk32508852017-01-18 09:17:13 -0500129 if (state.state != mState) {
Jason Monke5b770e2017-03-03 21:49:29 -0500130 int color = getColor(state.state);
Jason Monk32508852017-01-18 09:17:13 -0500131 mState = state.state;
Jason Monk9a82d122017-03-27 16:41:24 -0400132 if (iv.isShown() && mTint != 0) {
Jason Monk32508852017-01-18 09:17:13 -0500133 animateGrayScale(mTint, color, iv);
134 mTint = color;
135 } else {
136 setTint(iv, color);
137 mTint = color;
138 }
139 }
Jason Monkdc35dcb2015-12-04 16:36:15 -0500140 }
141
Jason Monke5b770e2017-03-03 21:49:29 -0500142 protected int getColor(int state) {
143 return getColorForState(getContext(), state);
144 }
145
Jason Monk32508852017-01-18 09:17:13 -0500146 public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
147 final float fromAlpha = Color.alpha(fromColor);
148 final float toAlpha = Color.alpha(toColor);
149 final float fromChannel = Color.red(fromColor);
150 final float toChannel = Color.red(toColor);
151
152 ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
Evan Laird8d2e5402017-06-08 10:36:57 -0400153 anim.setDuration(QS_ANIM_LENGTH);
Jason Monk32508852017-01-18 09:17:13 -0500154
155 anim.addUpdateListener(animation -> {
156 float fraction = animation.getAnimatedFraction();
157 int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction);
158 int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction);
159
160 setTint(iv, Color.argb(alpha, channel, channel, channel));
161 });
162 anim.start();
163 }
164
165 public static void setTint(ImageView iv, int color) {
166 iv.setImageTintList(ColorStateList.valueOf(color));
167 }
168
169
Jason Monkdc35dcb2015-12-04 16:36:15 -0500170 protected int getIconMeasureMode() {
171 return MeasureSpec.EXACTLY;
172 }
173
174 protected View createIcon() {
Jason Monk395617f2017-05-05 14:07:58 -0400175 final ImageView icon = new SlashImageView(mContext);
Jason Monkdc35dcb2015-12-04 16:36:15 -0500176 icon.setId(android.R.id.icon);
Jason Monkeae7c312016-02-04 13:00:48 -0500177 icon.setScaleType(ScaleType.FIT_CENTER);
Jason Monkdc35dcb2015-12-04 16:36:15 -0500178 return icon;
179 }
180
Xiaohui Chen2f3551b2016-04-07 10:37:25 -0700181 protected final int exactly(int size) {
Jason Monkdc35dcb2015-12-04 16:36:15 -0500182 return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
183 }
184
Xiaohui Chen2f3551b2016-04-07 10:37:25 -0700185 protected final void layout(View child, int left, int top) {
Jason Monkdc35dcb2015-12-04 16:36:15 -0500186 child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
187 }
188}