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; 24e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monkimport android.graphics.drawable.Animatable2; 25e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monkimport android.graphics.drawable.Animatable2.AnimationCallback; 26dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.graphics.drawable.Drawable; 27dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.view.View; 28dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport android.widget.ImageView; 29eae7c318864bcfd814c8be697315f829952ccc69Jason Monkimport android.widget.ImageView.ScaleType; 303250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk 31dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport com.android.systemui.R; 32702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkimport com.android.systemui.plugins.qs.QSIconView; 33702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkimport com.android.systemui.plugins.qs.QSTile; 34e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monkimport com.android.systemui.plugins.qs.QSTile.State; 35dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 366026b057e7e81a8e54e1986007360b2f97bf454fEvan Lairdimport com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashImageView; 37dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monkimport java.util.Objects; 38dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 39702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monkpublic class QSIconViewImpl extends QSIconView { 40dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 418d2e540854ce6d6660a83637b918660f6922f402Evan Laird public static final long QS_ANIM_LENGTH = 350; 428d2e540854ce6d6660a83637b918660f6922f402Evan Laird 432f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen protected final View mIcon; 442f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen protected final int mIconSizePx; 452f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen protected final int mTilePaddingBelowIconPx; 461aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk private boolean mAnimationEnabled = true; 473250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk private int mState = -1; 483250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk private int mTint; 49dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 50702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk public QSIconViewImpl(Context context) { 51dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk super(context); 52dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 53dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final Resources res = context.getResources(); 54dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mIconSizePx = res.getDimensionPixelSize(R.dimen.qs_tile_icon_size); 55dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mTilePaddingBelowIconPx = res.getDimensionPixelSize(R.dimen.qs_tile_padding_below_icon); 56dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 57dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mIcon = createIcon(); 58dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk addView(mIcon); 59dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 60dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 611aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk public void disableAnimation() { 621aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk mAnimationEnabled = false; 631aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk } 641aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk 652f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen public View getIconView() { 662f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen return mIcon; 672f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen } 682f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen 69dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk @Override 70dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 71dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int w = MeasureSpec.getSize(widthMeasureSpec); 72dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int iconSpec = exactly(mIconSizePx); 73dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk mIcon.measure(MeasureSpec.makeMeasureSpec(w, getIconMeasureMode()), iconSpec); 74dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setMeasuredDimension(w, mIcon.getMeasuredHeight() + mTilePaddingBelowIconPx); 75dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 76dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 77dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk @Override 78dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk protected void onLayout(boolean changed, int l, int t, int r, int b) { 79dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int w = getMeasuredWidth(); 80dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk int top = 0; 81dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2; 82dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk layout(mIcon, iconLeft, top); 83dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 84dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 85dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk public void setIcon(QSTile.State state) { 86dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk setIcon((ImageView) mIcon, state); 87dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 88dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 89e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk protected void updateIcon(ImageView iv, State state) { 90b3daf2b88c86243db85dd8425df8d3a59d3b3d4dEvan Laird final QSTile.Icon icon = state.iconSupplier != null ? state.iconSupplier.get() : state.icon; 91b3daf2b88c86243db85dd8425df8d3a59d3b3d4dEvan Laird if (!Objects.equals(icon, iv.getTag(R.id.qs_icon_tag)) 92395617fd35ef0e712945359a760a00eb1aaf7475Jason Monk || !Objects.equals(state.slash, iv.getTag(R.id.qs_slash_tag))) { 93da9395e681bfaa21692bcb4a7a249b1d7ff2e2d3Jason Monk boolean shouldAnimate = iv.isShown() && mAnimationEnabled 94da9395e681bfaa21692bcb4a7a249b1d7ff2e2d3Jason Monk && iv.getDrawable() != null; 95b3daf2b88c86243db85dd8425df8d3a59d3b3d4dEvan Laird Drawable d = icon != null 96b3daf2b88c86243db85dd8425df8d3a59d3b3d4dEvan Laird ? shouldAnimate ? icon.getDrawable(mContext) 97b3daf2b88c86243db85dd8425df8d3a59d3b3d4dEvan Laird : icon.getInvisibleDrawable(mContext) : null; 98b3daf2b88c86243db85dd8425df8d3a59d3b3d4dEvan Laird int padding = icon != null ? icon.getPadding() : 0; 99702e2ebf9fbfb715c1d9b716683c9e4d182b575eJason Monk if (d != null) { 100d686e9c26e84e56810fcf87f6002ba8ba2b3f0c5Jason Monk d.setAutoMirrored(false); 1013367c3353c11d5d9bd4ec8de21bdff24c6adb3b6Evan Laird d.setLayoutDirection(getLayoutDirection()); 102dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 103929bd54c6a91e78de4634cb50b781a9616157f5cEvan Laird 104929bd54c6a91e78de4634cb50b781a9616157f5cEvan Laird if (iv instanceof SlashImageView) { 105929bd54c6a91e78de4634cb50b781a9616157f5cEvan Laird ((SlashImageView) iv).setAnimationEnabled(shouldAnimate); 106929bd54c6a91e78de4634cb50b781a9616157f5cEvan Laird ((SlashImageView) iv).setState(state.slash, d); 107929bd54c6a91e78de4634cb50b781a9616157f5cEvan Laird } else { 108929bd54c6a91e78de4634cb50b781a9616157f5cEvan Laird iv.setImageDrawable(d); 109395617fd35ef0e712945359a760a00eb1aaf7475Jason Monk } 110929bd54c6a91e78de4634cb50b781a9616157f5cEvan Laird 111b3daf2b88c86243db85dd8425df8d3a59d3b3d4dEvan Laird iv.setTag(R.id.qs_icon_tag, icon); 112395617fd35ef0e712945359a760a00eb1aaf7475Jason Monk iv.setTag(R.id.qs_slash_tag, state.slash); 113b53b6c566f8e4754406cd1c3fddfa16a27515a7eJason Monk iv.setPadding(0, padding, 0, padding); 114e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk if (d instanceof Animatable2) { 115e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk Animatable2 a = (Animatable2) d; 11666239fbdfce1586555b339854b8a21f8187e805fJason Monk a.start(); 117e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk if (state.isTransient) { 118e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk a.registerAnimationCallback(new AnimationCallback() { 119e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk @Override 120e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk public void onAnimationEnd(Drawable drawable) { 121e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk a.start(); 122e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk } 123e645aee45a7784d772e4bdf846dd2e77335f30f2Jason Monk }); 124dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 125dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 126dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 127e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk } 128e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk 129e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk protected void setIcon(ImageView iv, QSTile.State state) { 130e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk updateIcon(iv, state); 1311c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka if (state.disabledByPolicy) { 1321c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color)); 1331c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka } else { 1341c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka iv.clearColorFilter(); 1351c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka } 1363250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk if (state.state != mState) { 137e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk int color = getColor(state.state); 1383250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk mState = state.state; 1399a82d124628350e64a835043baffced59ffcd143Jason Monk if (iv.isShown() && mTint != 0) { 1403250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk animateGrayScale(mTint, color, iv); 1413250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk mTint = color; 1423250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk } else { 1436026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird if (iv instanceof AlphaControlledSlashImageView) { 1446026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird ((AlphaControlledSlashImageView)iv) 1456026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird .setFinalImageTintList(ColorStateList.valueOf(color)); 1466026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird } else { 1476026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird setTint(iv, color); 1486026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird } 1493250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk mTint = color; 1503250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk } 1513250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk } 1523250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk } 1533250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk 154e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk protected int getColor(int state) { 155e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk return getColorForState(getContext(), state); 156e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk } 157e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk 1583250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk public static void animateGrayScale(int fromColor, int toColor, ImageView iv) { 1596026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird if (iv instanceof AlphaControlledSlashImageView) { 1606026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird ((AlphaControlledSlashImageView)iv) 1616026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird .setFinalImageTintList(ColorStateList.valueOf(toColor)); 1626026b057e7e81a8e54e1986007360b2f97bf454fEvan Laird } 163bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird if (ValueAnimator.areAnimatorsEnabled()) { 164bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird final float fromAlpha = Color.alpha(fromColor); 165bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird final float toAlpha = Color.alpha(toColor); 166bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird final float fromChannel = Color.red(fromColor); 167bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird final float toChannel = Color.red(toColor); 168bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird 169bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird ValueAnimator anim = ValueAnimator.ofFloat(0, 1); 170bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird anim.setDuration(QS_ANIM_LENGTH); 171bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird anim.addUpdateListener(animation -> { 172bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird float fraction = animation.getAnimatedFraction(); 173bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction); 174bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction); 175bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird 176bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird setTint(iv, Color.argb(alpha, channel, channel, channel)); 177bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird }); 178bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird 179bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird anim.start(); 180bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird } else { 181bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird setTint(iv, toColor); 182bdcd1cc85bdeaeb3b025073c995107d02a97caf7Evan Laird } 183dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 184dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 1853250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk public static void setTint(ImageView iv, int color) { 1863250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk iv.setImageTintList(ColorStateList.valueOf(color)); 1873250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk } 1883250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk 1893250885c9feb9b42d60058a823c57a027c0dcf58Jason Monk 190dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk protected int getIconMeasureMode() { 191dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk return MeasureSpec.EXACTLY; 192dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 193dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 194dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk protected View createIcon() { 195395617fd35ef0e712945359a760a00eb1aaf7475Jason Monk final ImageView icon = new SlashImageView(mContext); 196dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk icon.setId(android.R.id.icon); 197eae7c318864bcfd814c8be697315f829952ccc69Jason Monk icon.setScaleType(ScaleType.FIT_CENTER); 198dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk return icon; 199dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 200dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 2012f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen protected final int exactly(int size) { 202dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); 203dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 204dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk 2052f3551b04d5a5d05ba1eb7401f19c034708a9d00Xiaohui Chen protected final void layout(View child, int left, int top) { 206dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); 207dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk } 208dc35dcb14a8b6c4f221fccafffa5ca603894dbaaJason Monk} 209