blob: 3c1335456d04612eb16009548d2ae94cbc3f7878 [file] [log] [blame]
Joe Onorato0cbda992010-05-02 16:28:15 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Joe Onorato79de0c52010-05-26 17:03:26 -040017package com.android.systemui.statusbar;
Joe Onorato0cbda992010-05-02 16:28:15 -070018
Beverly1be62f42018-12-19 17:17:48 -050019import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
Evan Lairde1d13c92018-03-20 16:58:01 -040020
Selim Cinek49014f82016-11-04 14:55:30 -070021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
23import android.animation.ObjectAnimator;
Selim Cinek875ba9b2017-02-13 16:20:17 -080024import android.animation.ValueAnimator;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070025import android.app.Notification;
Joe Onorato0cbda992010-05-02 16:28:15 -070026import android.content.Context;
Adrian Roosa8e18ef2016-05-26 17:17:02 -070027import android.content.pm.ApplicationInfo;
Evan Lairde1d13c92018-03-20 16:58:01 -040028import android.content.res.ColorStateList;
Selim Cinek3e7592d2016-04-11 09:35:54 +080029import android.content.res.Configuration;
Joe Onorato0cbda992010-05-02 16:28:15 -070030import android.content.res.Resources;
Joe Onorato0cbda992010-05-02 16:28:15 -070031import android.graphics.Canvas;
Adrian Roos456e0052017-04-04 16:44:29 -070032import android.graphics.Color;
Adrian Roosc3e8cfc2017-07-17 17:09:39 +020033import android.graphics.ColorMatrixColorFilter;
Joe Onorato6c01a112010-10-04 17:38:47 -040034import android.graphics.Paint;
35import android.graphics.Rect;
John Spurlockde84f0e2013-06-12 12:41:00 -040036import android.graphics.drawable.Drawable;
Dan Sandlerd63f9322015-05-06 15:18:49 -040037import android.graphics.drawable.Icon;
Adrian Roosa8e18ef2016-05-26 17:17:02 -070038import android.os.Parcelable;
Jeff Sharkeyded653b2012-09-27 19:09:24 -070039import android.os.UserHandle;
Selim Cinek72fc8db2017-06-06 18:07:47 -070040import android.service.notification.StatusBarNotification;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070041import android.text.TextUtils;
Daniel Sandler05e24142011-11-10 11:56:49 -050042import android.util.AttributeSet;
Selim Cinek49014f82016-11-04 14:55:30 -070043import android.util.FloatProperty;
Joe Onoratof9ec03c2010-09-23 15:09:18 -070044import android.util.Log;
Selim Cinek49014f82016-11-04 14:55:30 -070045import android.util.Property;
Anthony Chen55e8e1e2016-01-08 10:31:46 -080046import android.util.TypedValue;
Joe Onorato0cbda992010-05-02 16:28:15 -070047import android.view.ViewDebug;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070048import android.view.accessibility.AccessibilityEvent;
Selim Cinek49014f82016-11-04 14:55:30 -070049import android.view.animation.Interpolator;
Winsonc0d70582016-01-29 10:24:39 -080050
Lucas Dupinde07d212018-10-23 17:47:03 -070051import androidx.core.graphics.ColorUtils;
52
Joe Onorato0cbda992010-05-02 16:28:15 -070053import com.android.internal.statusbar.StatusBarIcon;
Lucas Dupina291d192018-06-07 13:59:42 -070054import com.android.internal.util.ContrastColorUtil;
Selim Cinek49014f82016-11-04 14:55:30 -070055import com.android.systemui.Interpolators;
Joe Onorato6c01a112010-10-04 17:38:47 -040056import com.android.systemui.R;
Adrian Roos456e0052017-04-04 16:44:29 -070057import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
Selim Cinek49014f82016-11-04 14:55:30 -070058import com.android.systemui.statusbar.notification.NotificationUtils;
Joe Onorato6c01a112010-10-04 17:38:47 -040059
John Spurlockde84f0e2013-06-12 12:41:00 -040060import java.text.NumberFormat;
Adrian Roosc3e8cfc2017-07-17 17:09:39 +020061import java.util.Arrays;
John Spurlockde84f0e2013-06-12 12:41:00 -040062
Evan Lairde1d13c92018-03-20 16:58:01 -040063public class StatusBarIconView extends AnimatedImageView implements StatusIconDisplayable {
Selim Cinek875ba9b2017-02-13 16:20:17 -080064 public static final int NO_COLOR = 0;
Adrian Roosc3e8cfc2017-07-17 17:09:39 +020065
66 /**
67 * Multiply alpha values with (1+DARK_ALPHA_BOOST) when dozing. The chosen value boosts
68 * everything above 30% to 50%, making it appear on 1bit color depths.
69 */
70 private static final float DARK_ALPHA_BOOST = 0.67f;
Evan Laird39ea8102018-05-18 19:49:07 -040071 /**
72 * Status icons are currently drawn with the intention of being 17dp tall, but we
73 * want to scale them (in a way that doesn't require an asset dump) down 2dp. So
74 * 17dp * (15 / 17) = 15dp, the new height.
75 */
76 private static final float SYSTEM_ICON_SCALE = 15.f / 17.f;
Selim Cinek875ba9b2017-02-13 16:20:17 -080077 private final int ANIMATION_DURATION_FAST = 100;
78
Selim Cinek49014f82016-11-04 14:55:30 -070079 public static final int STATE_ICON = 0;
80 public static final int STATE_DOT = 1;
81 public static final int STATE_HIDDEN = 2;
Joe Onorato0cbda992010-05-02 16:28:15 -070082
Selim Cinek49014f82016-11-04 14:55:30 -070083 private static final String TAG = "StatusBarIconView";
84 private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
85 = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
86
87 @Override
88 public void setValue(StatusBarIconView object, float value) {
89 object.setIconAppearAmount(value);
90 }
91
92 @Override
93 public Float get(StatusBarIconView object) {
94 return object.getIconAppearAmount();
95 }
96 };
Selim Cinek5b5beb012016-11-08 18:11:58 -080097 private static final Property<StatusBarIconView, Float> DOT_APPEAR_AMOUNT
Selim Cinek49014f82016-11-04 14:55:30 -070098 = new FloatProperty<StatusBarIconView>("dot_appear_amount") {
99
100 @Override
101 public void setValue(StatusBarIconView object, float value) {
102 object.setDotAppearAmount(value);
103 }
104
105 @Override
106 public Float get(StatusBarIconView object) {
107 return object.getDotAppearAmount();
108 }
109 };
110
111 private boolean mAlwaysScaleIcon;
Adrian Roos138f0342017-04-28 09:11:28 -0700112 private int mStatusBarIconDrawingSizeDark = 1;
113 private int mStatusBarIconDrawingSize = 1;
114 private int mStatusBarIconSize = 1;
Joe Onorato0cbda992010-05-02 16:28:15 -0700115 private StatusBarIcon mIcon;
116 @ViewDebug.ExportedProperty private String mSlot;
Joe Onorato6c01a112010-10-04 17:38:47 -0400117 private Drawable mNumberBackground;
118 private Paint mNumberPain;
119 private int mNumberX;
120 private int mNumberY;
121 private String mNumberText;
Selim Cinek72fc8db2017-06-06 18:07:47 -0700122 private StatusBarNotification mNotification;
Jason Monk3b230072015-05-29 11:11:29 -0400123 private final boolean mBlocked;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800124 private int mDensity;
Lucas Dupinde07d212018-10-23 17:47:03 -0700125 private boolean mNightMode;
Selim Cinek281c2022016-10-13 19:14:43 -0700126 private float mIconScale = 1.0f;
Evan Lairdbaccb462018-06-01 16:29:02 -0400127 private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
Selim Cinek49014f82016-11-04 14:55:30 -0700128 private float mDotRadius;
129 private int mStaticDotRadius;
130 private int mVisibleState = STATE_ICON;
131 private float mIconAppearAmount = 1.0f;
132 private ObjectAnimator mIconAppearAnimator;
133 private ObjectAnimator mDotAnimator;
134 private float mDotAppearAmount;
Selim Cinek2b549f42016-11-22 16:38:51 -0800135 private OnVisibilityChangedListener mOnVisibilityChangedListener;
Selim Cinek875ba9b2017-02-13 16:20:17 -0800136 private int mDrawableColor;
137 private int mIconColor;
Adrian Roos456e0052017-04-04 16:44:29 -0700138 private int mDecorColor;
139 private float mDarkAmount;
Selim Cinek875ba9b2017-02-13 16:20:17 -0800140 private ValueAnimator mColorAnimator;
141 private int mCurrentSetColor = NO_COLOR;
142 private int mAnimationStartColor = NO_COLOR;
143 private final ValueAnimator.AnimatorUpdateListener mColorUpdater
144 = animation -> {
145 int newColor = NotificationUtils.interpolateColors(mAnimationStartColor, mIconColor,
146 animation.getAnimatedFraction());
147 setColorInternal(newColor);
148 };
Adrian Roos456e0052017-04-04 16:44:29 -0700149 private final NotificationIconDozeHelper mDozer;
Lucas Dupin83519da2017-06-21 11:58:31 -0700150 private int mContrastedDrawableColor;
151 private int mCachedContrastBackgroundColor = NO_COLOR;
Adrian Roosc3e8cfc2017-07-17 17:09:39 +0200152 private float[] mMatrix;
153 private ColorMatrixColorFilter mMatrixColorFilter;
Selim Cinekd95ca7c2017-07-26 12:20:38 -0700154 private boolean mIsInShelf;
Selim Cinek887da3c2017-10-06 13:37:32 -0700155 private Runnable mLayoutRunnable;
Selim Cinekd03518c2018-03-15 12:13:51 -0700156 private boolean mDismissed;
157 private Runnable mOnDismissListener;
Joe Onorato0cbda992010-05-02 16:28:15 -0700158
Selim Cinek72fc8db2017-06-06 18:07:47 -0700159 public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
160 this(context, slot, sbn, false);
Jason Monk3b230072015-05-29 11:11:29 -0400161 }
162
Selim Cinek72fc8db2017-06-06 18:07:47 -0700163 public StatusBarIconView(Context context, String slot, StatusBarNotification sbn,
Jason Monk3b230072015-05-29 11:11:29 -0400164 boolean blocked) {
Joe Onorato0cbda992010-05-02 16:28:15 -0700165 super(context);
Adrian Roos456e0052017-04-04 16:44:29 -0700166 mDozer = new NotificationIconDozeHelper(context);
Jason Monk3b230072015-05-29 11:11:29 -0400167 mBlocked = blocked;
Joe Onorato0cbda992010-05-02 16:28:15 -0700168 mSlot = slot;
Joe Onorato6c01a112010-10-04 17:38:47 -0400169 mNumberPain = new Paint();
170 mNumberPain.setTextAlign(Paint.Align.CENTER);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700171 mNumberPain.setColor(context.getColor(R.drawable.notification_number_text_color));
Joe Onorato6c01a112010-10-04 17:38:47 -0400172 mNumberPain.setAntiAlias(true);
Selim Cinek72fc8db2017-06-06 18:07:47 -0700173 setNotification(sbn);
Selim Cinek3e7592d2016-04-11 09:35:54 +0800174 setScaleType(ScaleType.CENTER);
175 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Lucas Dupinde07d212018-10-23 17:47:03 -0700176 Configuration configuration = context.getResources().getConfiguration();
177 mNightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
178 == Configuration.UI_MODE_NIGHT_YES;
179 initializeDecorColor();
Selim Cinek49014f82016-11-04 14:55:30 -0700180 reloadDimens();
Evan Laird20b87bf2018-04-12 09:54:11 -0400181 maybeUpdateIconScaleDimens();
Selim Cinek3e7592d2016-04-11 09:35:54 +0800182 }
Daniel Sandler26c84b12011-07-27 00:09:40 -0400183
Evan Laird20b87bf2018-04-12 09:54:11 -0400184 /** Should always be preceded by {@link #reloadDimens()} */
Adrian Roos138f0342017-04-28 09:11:28 -0700185 private void maybeUpdateIconScaleDimens() {
Daniel Sandler7579bca2011-08-18 15:47:26 -0400186 // We do not resize and scale system icons (on the right), only notification icons (on the
187 // left).
Selim Cinek3e7592d2016-04-11 09:35:54 +0800188 if (mNotification != null || mAlwaysScaleIcon) {
Evan Laird39ea8102018-05-18 19:49:07 -0400189 updateIconScaleForNotifications();
190 } else {
191 updateIconScaleForSystemIcons();
Daniel Sandler7579bca2011-08-18 15:47:26 -0400192 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800193 }
Daniel Sandlerabff0322011-09-27 11:19:34 -0400194
Evan Laird39ea8102018-05-18 19:49:07 -0400195 private void updateIconScaleForNotifications() {
Adrian Roos138f0342017-04-28 09:11:28 -0700196 final float imageBounds = NotificationUtils.interpolate(
197 mStatusBarIconDrawingSize,
198 mStatusBarIconDrawingSizeDark,
199 mDarkAmount);
200 final int outerBounds = mStatusBarIconSize;
Selim Cinek281c2022016-10-13 19:14:43 -0700201 mIconScale = (float)imageBounds / (float)outerBounds;
Selim Cinek3ddda6d2018-06-08 00:26:48 -0700202 updatePivot();
Selim Cinek281c2022016-10-13 19:14:43 -0700203 }
204
Evan Laird39ea8102018-05-18 19:49:07 -0400205 private void updateIconScaleForSystemIcons() {
206 mIconScale = SYSTEM_ICON_SCALE;
207 }
208
Selim Cinek281c2022016-10-13 19:14:43 -0700209 public float getIconScale() {
210 return mIconScale;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800211 }
212
213 @Override
214 protected void onConfigurationChanged(Configuration newConfig) {
215 super.onConfigurationChanged(newConfig);
216 int density = newConfig.densityDpi;
217 if (density != mDensity) {
218 mDensity = density;
Evan Laird20b87bf2018-04-12 09:54:11 -0400219 reloadDimens();
Adrian Roos138f0342017-04-28 09:11:28 -0700220 maybeUpdateIconScaleDimens();
Selim Cinek3e7592d2016-04-11 09:35:54 +0800221 updateDrawable();
Selim Cinek49014f82016-11-04 14:55:30 -0700222 }
Lucas Dupinde07d212018-10-23 17:47:03 -0700223 boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
224 == Configuration.UI_MODE_NIGHT_YES;
225 if (nightMode != mNightMode) {
226 mNightMode = nightMode;
227 initializeDecorColor();
228 }
Selim Cinek49014f82016-11-04 14:55:30 -0700229 }
230
231 private void reloadDimens() {
232 boolean applyRadius = mDotRadius == mStaticDotRadius;
Evan Laird20b87bf2018-04-12 09:54:11 -0400233 Resources res = getResources();
234 mStaticDotRadius = res.getDimensionPixelSize(R.dimen.overflow_dot_radius);
235 mStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
236 mStatusBarIconDrawingSizeDark =
237 res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark);
238 mStatusBarIconDrawingSize =
239 res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
Selim Cinek49014f82016-11-04 14:55:30 -0700240 if (applyRadius) {
241 mDotRadius = mStaticDotRadius;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800242 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700243 }
244
Selim Cinek72fc8db2017-06-06 18:07:47 -0700245 public void setNotification(StatusBarNotification notification) {
Christoph Studera0506e72014-07-31 20:27:39 +0200246 mNotification = notification;
Selim Cinek72fc8db2017-06-06 18:07:47 -0700247 if (notification != null) {
248 setContentDescription(notification.getNotification());
249 }
Christoph Studera0506e72014-07-31 20:27:39 +0200250 }
251
Daniel Sandler05e24142011-11-10 11:56:49 -0500252 public StatusBarIconView(Context context, AttributeSet attrs) {
253 super(context, attrs);
Adrian Roos456e0052017-04-04 16:44:29 -0700254 mDozer = new NotificationIconDozeHelper(context);
Jason Monk3b230072015-05-29 11:11:29 -0400255 mBlocked = false;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800256 mAlwaysScaleIcon = true;
Evan Laird20b87bf2018-04-12 09:54:11 -0400257 reloadDimens();
Evan Laird39ea8102018-05-18 19:49:07 -0400258 updateIconScaleForNotifications();
Selim Cinek3e7592d2016-04-11 09:35:54 +0800259 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Daniel Sandler05e24142011-11-10 11:56:49 -0500260 }
261
Joe Onorato0cbda992010-05-02 16:28:15 -0700262 private static boolean streq(String a, String b) {
Joe Onorato66d7d012010-05-14 10:05:10 -0700263 if (a == b) {
264 return true;
265 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700266 if (a == null && b != null) {
267 return false;
268 }
269 if (a != null && b == null) {
270 return false;
271 }
272 return a.equals(b);
273 }
274
Dan Sandlerd63f9322015-05-06 15:18:49 -0400275 public boolean equalIcons(Icon a, Icon b) {
276 if (a == b) return true;
277 if (a.getType() != b.getType()) return false;
278 switch (a.getType()) {
279 case Icon.TYPE_RESOURCE:
280 return a.getResPackage().equals(b.getResPackage()) && a.getResId() == b.getResId();
281 case Icon.TYPE_URI:
282 return a.getUriString().equals(b.getUriString());
283 default:
284 return false;
285 }
286 }
Joe Onorato005847b2010-06-04 16:08:02 -0400287 /**
288 * Returns whether the set succeeded.
289 */
290 public boolean set(StatusBarIcon icon) {
Dan Sandlerd63f9322015-05-06 15:18:49 -0400291 final boolean iconEquals = mIcon != null && equalIcons(mIcon.icon, icon.icon);
Joe Onorato005847b2010-06-04 16:08:02 -0400292 final boolean levelEquals = iconEquals
293 && mIcon.iconLevel == icon.iconLevel;
294 final boolean visibilityEquals = mIcon != null
295 && mIcon.visible == icon.visible;
Joe Onorato6c01a112010-10-04 17:38:47 -0400296 final boolean numberEquals = mIcon != null
297 && mIcon.number == icon.number;
298 mIcon = icon.clone();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700299 setContentDescription(icon.contentDescription);
Joe Onorato005847b2010-06-04 16:08:02 -0400300 if (!iconEquals) {
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800301 if (!updateDrawable(false /* no clear */)) return false;
Selim Cinek2b6eb8032016-12-29 14:22:21 +0100302 // we have to clear the grayscale tag since it may have changed
303 setTag(R.id.icon_is_grayscale, null);
Joe Onorato0cbda992010-05-02 16:28:15 -0700304 }
Joe Onorato005847b2010-06-04 16:08:02 -0400305 if (!levelEquals) {
306 setImageLevel(icon.iconLevel);
Joe Onorato0cbda992010-05-02 16:28:15 -0700307 }
Daniel Sandler26c84b12011-07-27 00:09:40 -0400308
Joe Onorato6c01a112010-10-04 17:38:47 -0400309 if (!numberEquals) {
John Spurlock01534782014-01-13 11:59:22 -0500310 if (icon.number > 0 && getContext().getResources().getBoolean(
Joe Onorato8595a3d2010-11-19 18:12:07 -0800311 R.bool.config_statusBarShowNumber)) {
Joe Onorato6c01a112010-10-04 17:38:47 -0400312 if (mNumberBackground == null) {
313 mNumberBackground = getContext().getResources().getDrawable(
314 R.drawable.ic_notification_overlay);
315 }
316 placeNumber();
317 } else {
318 mNumberBackground = null;
319 mNumberText = null;
320 }
321 invalidate();
322 }
Joe Onorato005847b2010-06-04 16:08:02 -0400323 if (!visibilityEquals) {
Jason Monk3b230072015-05-29 11:11:29 -0400324 setVisibility(icon.visible && !mBlocked ? VISIBLE : GONE);
Joe Onorato005847b2010-06-04 16:08:02 -0400325 }
Joe Onorato005847b2010-06-04 16:08:02 -0400326 return true;
Joe Onorato0cbda992010-05-02 16:28:15 -0700327 }
328
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800329 public void updateDrawable() {
330 updateDrawable(true /* with clear */);
331 }
332
333 private boolean updateDrawable(boolean withClear) {
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100334 if (mIcon == null) {
335 return false;
336 }
Adrian Roosfb2d0cc2017-01-31 15:10:00 -0800337 Drawable drawable;
338 try {
339 drawable = getIcon(mIcon);
340 } catch (OutOfMemoryError e) {
341 Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
342 return false;
343 }
344
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800345 if (drawable == null) {
Adrian Roosfb2d0cc2017-01-31 15:10:00 -0800346 Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800347 return false;
348 }
349 if (withClear) {
350 setImageDrawable(null);
351 }
352 setImageDrawable(drawable);
353 return true;
354 }
355
Selim Cinek72fc8db2017-06-06 18:07:47 -0700356 public Icon getSourceIcon() {
357 return mIcon.icon;
358 }
359
Joe Onoratof5510542010-06-01 07:46:41 -0700360 private Drawable getIcon(StatusBarIcon icon) {
361 return getIcon(getContext(), icon);
362 }
363
Joe Onorato0cbda992010-05-02 16:28:15 -0700364 /**
Dan Sandlerd63f9322015-05-06 15:18:49 -0400365 * Returns the right icon to use for this item
John Spurlock209bede2013-07-17 12:23:27 -0400366 *
Dan Sandlerd63f9322015-05-06 15:18:49 -0400367 * @param context Context to use to get resources
Joe Onorato0cbda992010-05-02 16:28:15 -0700368 * @return Drawable for this item, or null if the package or item could not
369 * be found
370 */
Anthony Chen55e8e1e2016-01-08 10:31:46 -0800371 public static Drawable getIcon(Context context, StatusBarIcon statusBarIcon) {
372 int userId = statusBarIcon.user.getIdentifier();
Dan Sandlerd63f9322015-05-06 15:18:49 -0400373 if (userId == UserHandle.USER_ALL) {
Xiaohui Chen87d0e252015-07-30 15:38:16 -0700374 userId = UserHandle.USER_SYSTEM;
Joe Onorato0cbda992010-05-02 16:28:15 -0700375 }
Anthony Chen55e8e1e2016-01-08 10:31:46 -0800376
377 Drawable icon = statusBarIcon.icon.loadDrawableAsUser(context, userId);
378
379 TypedValue typedValue = new TypedValue();
380 context.getResources().getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
381 float scaleFactor = typedValue.getFloat();
382
383 // No need to scale the icon, so return it as is.
384 if (scaleFactor == 1.f) {
385 return icon;
386 }
387
388 return new ScalingDrawableWrapper(icon, scaleFactor);
Joe Onorato0cbda992010-05-02 16:28:15 -0700389 }
Joe Onoratob77f53b2010-05-28 19:59:51 -0400390
391 public StatusBarIcon getStatusBarIcon() {
392 return mIcon;
393 }
Joe Onoratof9ec03c2010-09-23 15:09:18 -0700394
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700395 @Override
396 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
397 super.onInitializeAccessibilityEvent(event);
398 if (mNotification != null) {
Selim Cinek72fc8db2017-06-06 18:07:47 -0700399 event.setParcelableData(mNotification.getNotification());
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700400 }
401 }
402
403 @Override
Joe Onorato6c01a112010-10-04 17:38:47 -0400404 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
405 super.onSizeChanged(w, h, oldw, oldh);
406 if (mNumberBackground != null) {
407 placeNumber();
408 }
409 }
410
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700411 @Override
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100412 public void onRtlPropertiesChanged(int layoutDirection) {
413 super.onRtlPropertiesChanged(layoutDirection);
414 updateDrawable();
415 }
416
417 @Override
Joe Onorato6c01a112010-10-04 17:38:47 -0400418 protected void onDraw(Canvas canvas) {
Selim Cinek49014f82016-11-04 14:55:30 -0700419 if (mIconAppearAmount > 0.0f) {
420 canvas.save();
421 canvas.scale(mIconScale * mIconAppearAmount, mIconScale * mIconAppearAmount,
422 getWidth() / 2, getHeight() / 2);
423 super.onDraw(canvas);
424 canvas.restore();
425 }
Joe Onorato6c01a112010-10-04 17:38:47 -0400426
427 if (mNumberBackground != null) {
428 mNumberBackground.draw(canvas);
429 canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain);
430 }
Selim Cinek49014f82016-11-04 14:55:30 -0700431 if (mDotAppearAmount != 0.0f) {
432 float radius;
Evan Lairdbaccb462018-06-01 16:29:02 -0400433 float alpha = Color.alpha(mDecorColor) / 255.f;
Selim Cinek49014f82016-11-04 14:55:30 -0700434 if (mDotAppearAmount <= 1.0f) {
435 radius = mDotRadius * mDotAppearAmount;
Selim Cinek49014f82016-11-04 14:55:30 -0700436 } else {
437 float fadeOutAmount = mDotAppearAmount - 1.0f;
Evan Lairdbaccb462018-06-01 16:29:02 -0400438 alpha = alpha * (1.0f - fadeOutAmount);
Selim Cinek49014f82016-11-04 14:55:30 -0700439 radius = NotificationUtils.interpolate(mDotRadius, getWidth() / 4, fadeOutAmount);
440 }
441 mDotPaint.setAlpha((int) (alpha * 255));
Evan Laird20b87bf2018-04-12 09:54:11 -0400442 canvas.drawCircle(mStatusBarIconSize / 2, getHeight() / 2, radius, mDotPaint);
Selim Cinek49014f82016-11-04 14:55:30 -0700443 }
Joe Onorato6c01a112010-10-04 17:38:47 -0400444 }
445
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700446 @Override
Joe Onoratof9ec03c2010-09-23 15:09:18 -0700447 protected void debug(int depth) {
448 super.debug(depth);
449 Log.d("View", debugIndent(depth) + "slot=" + mSlot);
450 Log.d("View", debugIndent(depth) + "icon=" + mIcon);
451 }
Joe Onorato6c01a112010-10-04 17:38:47 -0400452
453 void placeNumber() {
Daniel Sandlerebce0112011-06-16 16:44:51 -0400454 final String str;
John Spurlock01534782014-01-13 11:59:22 -0500455 final int tooBig = getContext().getResources().getInteger(
Daniel Sandlerebce0112011-06-16 16:44:51 -0400456 android.R.integer.status_bar_notification_info_maxnum);
457 if (mIcon.number > tooBig) {
John Spurlock01534782014-01-13 11:59:22 -0500458 str = getContext().getResources().getString(
Daniel Sandlerebce0112011-06-16 16:44:51 -0400459 android.R.string.status_bar_notification_info_overflow);
460 } else {
461 NumberFormat f = NumberFormat.getIntegerInstance();
462 str = f.format(mIcon.number);
463 }
464 mNumberText = str;
465
Joe Onorato6c01a112010-10-04 17:38:47 -0400466 final int w = getWidth();
467 final int h = getHeight();
468 final Rect r = new Rect();
469 mNumberPain.getTextBounds(str, 0, str.length(), r);
470 final int tw = r.right - r.left;
471 final int th = r.bottom - r.top;
472 mNumberBackground.getPadding(r);
473 int dw = r.left + tw + r.right;
474 if (dw < mNumberBackground.getMinimumWidth()) {
475 dw = mNumberBackground.getMinimumWidth();
476 }
477 mNumberX = w-r.right-((dw-r.right-r.left)/2);
478 int dh = r.top + th + r.bottom;
479 if (dh < mNumberBackground.getMinimumWidth()) {
480 dh = mNumberBackground.getMinimumWidth();
481 }
482 mNumberY = h-r.bottom-((dh-r.top-th-r.bottom)/2);
483 mNumberBackground.setBounds(w-dw, h-dh, w, h);
484 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700485
486 private void setContentDescription(Notification notification) {
487 if (notification != null) {
Adrian Rooseba05822016-04-22 17:09:27 -0700488 String d = contentDescForNotification(mContext, notification);
489 if (!TextUtils.isEmpty(d)) {
490 setContentDescription(d);
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700491 }
492 }
493 }
Daniel Sandler7579bca2011-08-18 15:47:26 -0400494
495 public String toString() {
John Spurlock209bede2013-07-17 12:23:27 -0400496 return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon
Daniel Sandler7579bca2011-08-18 15:47:26 -0400497 + " notification=" + mNotification + ")";
498 }
Jason Monk3b230072015-05-29 11:11:29 -0400499
Selim Cinek72fc8db2017-06-06 18:07:47 -0700500 public StatusBarNotification getNotification() {
501 return mNotification;
502 }
503
Jason Monk3b230072015-05-29 11:11:29 -0400504 public String getSlot() {
505 return mSlot;
506 }
Adrian Rooseba05822016-04-22 17:09:27 -0700507
508
509 public static String contentDescForNotification(Context c, Notification n) {
Adrian Roosa8e18ef2016-05-26 17:17:02 -0700510 String appName = "";
511 try {
512 Notification.Builder builder = Notification.Builder.recoverBuilder(c, n);
513 appName = builder.loadHeaderAppName();
514 } catch (RuntimeException e) {
515 Log.e(TAG, "Unable to recover builder", e);
516 // Trying to get the app name from the app info instead.
517 Parcelable appInfo = n.extras.getParcelable(
518 Notification.EXTRA_BUILDER_APPLICATION_INFO);
519 if (appInfo instanceof ApplicationInfo) {
520 appName = String.valueOf(((ApplicationInfo) appInfo).loadLabel(
521 c.getPackageManager()));
522 }
523 }
Adrian Roos51548e62016-04-28 11:20:26 -0700524
Julia Reynolds7f9ce782016-05-17 15:34:34 -0400525 CharSequence title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
Adrian Roosf76600e2017-04-19 15:32:43 -0700526 CharSequence text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
Adrian Rooseba05822016-04-22 17:09:27 -0700527 CharSequence ticker = n.tickerText;
Adrian Roos51548e62016-04-28 11:20:26 -0700528
Adrian Roosf76600e2017-04-19 15:32:43 -0700529 // Some apps just put the app name into the title
530 CharSequence titleOrText = TextUtils.equals(title, appName) ? text : title;
531
532 CharSequence desc = !TextUtils.isEmpty(titleOrText) ? titleOrText
Adrian Roos6e782a52017-03-30 18:34:10 -0700533 : !TextUtils.isEmpty(ticker) ? ticker : "";
Adrian Roos51548e62016-04-28 11:20:26 -0700534
535 return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
Adrian Rooseba05822016-04-22 17:09:27 -0700536 }
Adrian Roos51548e62016-04-28 11:20:26 -0700537
Selim Cinek875ba9b2017-02-13 16:20:17 -0800538 /**
539 * Set the color that is used to draw decoration like the overflow dot. This will not be applied
540 * to the drawable.
541 */
542 public void setDecorColor(int iconTint) {
Adrian Roos456e0052017-04-04 16:44:29 -0700543 mDecorColor = iconTint;
544 updateDecorColor();
545 }
546
Lucas Dupinde07d212018-10-23 17:47:03 -0700547 private void initializeDecorColor() {
548 if (mNotification != null) {
549 setDecorColor(getContext().getColor(mNightMode
550 ? com.android.internal.R.color.notification_default_color_dark
551 : com.android.internal.R.color.notification_default_color_light));
552 }
553 }
554
Adrian Roos456e0052017-04-04 16:44:29 -0700555 private void updateDecorColor() {
556 int color = NotificationUtils.interpolateColors(mDecorColor, Color.WHITE, mDarkAmount);
557 if (mDotPaint.getColor() != color) {
558 mDotPaint.setColor(color);
559
560 if (mDotAppearAmount != 0) {
561 invalidate();
562 }
563 }
Selim Cinek49014f82016-11-04 14:55:30 -0700564 }
565
Selim Cinek875ba9b2017-02-13 16:20:17 -0800566 /**
567 * Set the static color that should be used for the drawable of this icon if it's not
568 * transitioning this also immediately sets the color.
569 */
570 public void setStaticDrawableColor(int color) {
571 mDrawableColor = color;
572 setColorInternal(color);
Lucas Dupin83519da2017-06-21 11:58:31 -0700573 updateContrastedStaticColor();
Selim Cinek875ba9b2017-02-13 16:20:17 -0800574 mIconColor = color;
Adrian Roos456e0052017-04-04 16:44:29 -0700575 mDozer.setColor(color);
Selim Cinek875ba9b2017-02-13 16:20:17 -0800576 }
577
578 private void setColorInternal(int color) {
Adrian Roosf3eacd32017-04-14 16:35:58 -0700579 mCurrentSetColor = color;
580 updateIconColor();
581 }
582
583 private void updateIconColor() {
584 if (mCurrentSetColor != NO_COLOR) {
Adrian Roosc3e8cfc2017-07-17 17:09:39 +0200585 if (mMatrixColorFilter == null) {
586 mMatrix = new float[4 * 5];
587 mMatrixColorFilter = new ColorMatrixColorFilter(mMatrix);
588 }
589 int color = NotificationUtils.interpolateColors(
590 mCurrentSetColor, Color.WHITE, mDarkAmount);
591 updateTintMatrix(mMatrix, color, DARK_ALPHA_BOOST * mDarkAmount);
592 mMatrixColorFilter.setColorMatrixArray(mMatrix);
593 setColorFilter(mMatrixColorFilter);
594 invalidate(); // setColorFilter only invalidates if the filter instance changed.
Selim Cinek875ba9b2017-02-13 16:20:17 -0800595 } else {
Adrian Roosf3eacd32017-04-14 16:35:58 -0700596 mDozer.updateGrayscale(this, mDarkAmount);
Selim Cinek875ba9b2017-02-13 16:20:17 -0800597 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800598 }
599
Adrian Roosc3e8cfc2017-07-17 17:09:39 +0200600 /**
601 * Updates {@param array} such that it represents a matrix that changes RGB to {@param color}
Adrian Roos24dbff32017-08-02 16:57:11 +0200602 * and multiplies the alpha channel with the color's alpha+{@param alphaBoost}.
Adrian Roosc3e8cfc2017-07-17 17:09:39 +0200603 */
604 private static void updateTintMatrix(float[] array, int color, float alphaBoost) {
605 Arrays.fill(array, 0);
606 array[4] = Color.red(color);
607 array[9] = Color.green(color);
608 array[14] = Color.blue(color);
Adrian Roos24dbff32017-08-02 16:57:11 +0200609 array[18] = Color.alpha(color) / 255f + alphaBoost;
Adrian Roosc3e8cfc2017-07-17 17:09:39 +0200610 }
611
Selim Cinek875ba9b2017-02-13 16:20:17 -0800612 public void setIconColor(int iconColor, boolean animate) {
613 if (mIconColor != iconColor) {
614 mIconColor = iconColor;
615 if (mColorAnimator != null) {
616 mColorAnimator.cancel();
617 }
618 if (mCurrentSetColor == iconColor) {
619 return;
620 }
621 if (animate && mCurrentSetColor != NO_COLOR) {
622 mAnimationStartColor = mCurrentSetColor;
623 mColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
624 mColorAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
625 mColorAnimator.setDuration(ANIMATION_DURATION_FAST);
626 mColorAnimator.addUpdateListener(mColorUpdater);
627 mColorAnimator.addListener(new AnimatorListenerAdapter() {
628 @Override
629 public void onAnimationEnd(Animator animation) {
630 mColorAnimator = null;
631 mAnimationStartColor = NO_COLOR;
632 }
633 });
634 mColorAnimator.start();
635 } else {
636 setColorInternal(iconColor);
637 }
638 }
639 }
640
641 public int getStaticDrawableColor() {
642 return mDrawableColor;
643 }
644
Lucas Dupin83519da2017-06-21 11:58:31 -0700645 /**
646 * A drawable color that passes GAR on a specific background.
647 * This value is cached.
648 *
649 * @param backgroundColor Background to test against.
650 * @return GAR safe version of {@link StatusBarIconView#getStaticDrawableColor()}.
651 */
652 int getContrastedStaticDrawableColor(int backgroundColor) {
653 if (mCachedContrastBackgroundColor != backgroundColor) {
654 mCachedContrastBackgroundColor = backgroundColor;
655 updateContrastedStaticColor();
656 }
657 return mContrastedDrawableColor;
658 }
659
660 private void updateContrastedStaticColor() {
Lucas Dupinddbaf842017-06-23 09:30:49 -0700661 if (Color.alpha(mCachedContrastBackgroundColor) != 255) {
662 mContrastedDrawableColor = mDrawableColor;
Lucas Dupin83519da2017-06-21 11:58:31 -0700663 return;
664 }
665 // We'll modify the color if it doesn't pass GAR
666 int contrastedColor = mDrawableColor;
Lucas Dupina291d192018-06-07 13:59:42 -0700667 if (!ContrastColorUtil.satisfiesTextContrast(mCachedContrastBackgroundColor,
Lucas Dupin83519da2017-06-21 11:58:31 -0700668 contrastedColor)) {
669 float[] hsl = new float[3];
670 ColorUtils.colorToHSL(mDrawableColor, hsl);
671 // This is basically a light grey, pushing the color will only distort it.
672 // Best thing to do in here is to fallback to the default color.
673 if (hsl[1] < 0.2f) {
674 contrastedColor = Notification.COLOR_DEFAULT;
675 }
Lucas Dupinf03e7522018-06-25 16:21:13 -0700676 boolean isDark = !ContrastColorUtil.isColorLight(mCachedContrastBackgroundColor);
Lucas Dupina291d192018-06-07 13:59:42 -0700677 contrastedColor = ContrastColorUtil.resolveContrastColor(mContext,
Lucas Dupinf03e7522018-06-25 16:21:13 -0700678 contrastedColor, mCachedContrastBackgroundColor, isDark);
Lucas Dupin83519da2017-06-21 11:58:31 -0700679 }
680 mContrastedDrawableColor = contrastedColor;
681 }
682
Evan Laird20b87bf2018-04-12 09:54:11 -0400683 @Override
Selim Cinek5b5beb012016-11-08 18:11:58 -0800684 public void setVisibleState(int state) {
685 setVisibleState(state, true /* animate */, null /* endRunnable */);
686 }
687
688 public void setVisibleState(int state, boolean animate) {
689 setVisibleState(state, animate, null);
690 }
691
692 @Override
693 public boolean hasOverlappingRendering() {
694 return false;
695 }
696
697 public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700698 setVisibleState(visibleState, animate, endRunnable, 0);
699 }
700
701 /**
702 * Set the visibleState of this view.
703 *
704 * @param visibleState The new state.
705 * @param animate Should we animate?
706 * @param endRunnable The runnable to run at the end.
707 * @param duration The duration of an animation or 0 if the default should be taken.
708 */
709 public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable,
710 long duration) {
Selim Cinek65d418e2016-11-29 15:42:34 -0800711 boolean runnableAdded = false;
Selim Cinek49014f82016-11-04 14:55:30 -0700712 if (visibleState != mVisibleState) {
713 mVisibleState = visibleState;
Selim Cinek5ece5a72017-02-15 11:47:42 -0800714 if (mIconAppearAnimator != null) {
715 mIconAppearAnimator.cancel();
716 }
717 if (mDotAnimator != null) {
718 mDotAnimator.cancel();
719 }
Selim Cinek5b5beb012016-11-08 18:11:58 -0800720 if (animate) {
Selim Cinek5b5beb012016-11-08 18:11:58 -0800721 float targetAmount = 0.0f;
722 Interpolator interpolator = Interpolators.FAST_OUT_LINEAR_IN;
723 if (visibleState == STATE_ICON) {
724 targetAmount = 1.0f;
725 interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
726 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800727 float currentAmount = getIconAppearAmount();
728 if (targetAmount != currentAmount) {
729 mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
730 currentAmount, targetAmount);
731 mIconAppearAnimator.setInterpolator(interpolator);
Selim Cinekd03518c2018-03-15 12:13:51 -0700732 mIconAppearAnimator.setDuration(duration == 0 ? ANIMATION_DURATION_FAST
733 : duration);
Selim Cinek65d418e2016-11-29 15:42:34 -0800734 mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
735 @Override
736 public void onAnimationEnd(Animator animation) {
737 mIconAppearAnimator = null;
738 runRunnable(endRunnable);
Selim Cinek5b5beb012016-11-08 18:11:58 -0800739 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800740 });
741 mIconAppearAnimator.start();
742 runnableAdded = true;
743 }
Selim Cinek49014f82016-11-04 14:55:30 -0700744
Selim Cinek5b5beb012016-11-08 18:11:58 -0800745 targetAmount = visibleState == STATE_ICON ? 2.0f : 0.0f;
746 interpolator = Interpolators.FAST_OUT_LINEAR_IN;
747 if (visibleState == STATE_DOT) {
748 targetAmount = 1.0f;
749 interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
750 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800751 currentAmount = getDotAppearAmount();
752 if (targetAmount != currentAmount) {
753 mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
754 currentAmount, targetAmount);
Selim Cinekd03518c2018-03-15 12:13:51 -0700755 mDotAnimator.setInterpolator(interpolator);;
756 mDotAnimator.setDuration(duration == 0 ? ANIMATION_DURATION_FAST
757 : duration);
Selim Cinek65d418e2016-11-29 15:42:34 -0800758 final boolean runRunnable = !runnableAdded;
759 mDotAnimator.addListener(new AnimatorListenerAdapter() {
760 @Override
761 public void onAnimationEnd(Animator animation) {
762 mDotAnimator = null;
763 if (runRunnable) {
764 runRunnable(endRunnable);
765 }
766 }
767 });
768 mDotAnimator.start();
769 runnableAdded = true;
770 }
Selim Cinek5b5beb012016-11-08 18:11:58 -0800771 } else {
772 setIconAppearAmount(visibleState == STATE_ICON ? 1.0f : 0.0f);
Selim Cinek01a73f92016-12-06 16:13:42 -0800773 setDotAppearAmount(visibleState == STATE_DOT ? 1.0f
774 : visibleState == STATE_ICON ? 2.0f
775 : 0.0f);
Selim Cinek5b5beb012016-11-08 18:11:58 -0800776 }
Selim Cinek49014f82016-11-04 14:55:30 -0700777 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800778 if (!runnableAdded) {
779 runRunnable(endRunnable);
780 }
781 }
782
783 private void runRunnable(Runnable runnable) {
784 if (runnable != null) {
785 runnable.run();
786 }
Selim Cinek49014f82016-11-04 14:55:30 -0700787 }
788
Selim Cinek5b5beb012016-11-08 18:11:58 -0800789 public void setIconAppearAmount(float iconAppearAmount) {
Selim Cinek9ef119c2017-03-01 15:13:36 -0800790 if (mIconAppearAmount != iconAppearAmount) {
791 mIconAppearAmount = iconAppearAmount;
792 invalidate();
793 }
Selim Cinek49014f82016-11-04 14:55:30 -0700794 }
795
796 public float getIconAppearAmount() {
797 return mIconAppearAmount;
798 }
799
800 public int getVisibleState() {
801 return mVisibleState;
802 }
803
804 public void setDotAppearAmount(float dotAppearAmount) {
Selim Cinek9ef119c2017-03-01 15:13:36 -0800805 if (mDotAppearAmount != dotAppearAmount) {
806 mDotAppearAmount = dotAppearAmount;
807 invalidate();
808 }
Selim Cinek49014f82016-11-04 14:55:30 -0700809 }
810
Selim Cinek2b549f42016-11-22 16:38:51 -0800811 @Override
812 public void setVisibility(int visibility) {
813 super.setVisibility(visibility);
814 if (mOnVisibilityChangedListener != null) {
815 mOnVisibilityChangedListener.onVisibilityChanged(visibility);
816 }
817 }
818
Selim Cinek49014f82016-11-04 14:55:30 -0700819 public float getDotAppearAmount() {
820 return mDotAppearAmount;
821 }
Selim Cinek2b549f42016-11-22 16:38:51 -0800822
823 public void setOnVisibilityChangedListener(OnVisibilityChangedListener listener) {
824 mOnVisibilityChangedListener = listener;
825 }
826
Adrian Roos456e0052017-04-04 16:44:29 -0700827 public void setDark(boolean dark, boolean fade, long delay) {
Adrian Roos456e0052017-04-04 16:44:29 -0700828 mDozer.setIntensityDark(f -> {
829 mDarkAmount = f;
Evan Laird39ea8102018-05-18 19:49:07 -0400830 updateIconScaleForNotifications();
Adrian Roos456e0052017-04-04 16:44:29 -0700831 updateDecorColor();
Adrian Roosf3eacd32017-04-14 16:35:58 -0700832 updateIconColor();
Adrian Roosfe0071f2017-07-06 18:45:10 +0200833 updateAllowAnimation();
Selim Cinek653c1392018-05-15 13:02:42 -0700834 }, dark, fade, delay, this);
Adrian Roos456e0052017-04-04 16:44:29 -0700835 }
836
Adrian Roosfe0071f2017-07-06 18:45:10 +0200837 private void updateAllowAnimation() {
838 if (mDarkAmount == 0 || mDarkAmount == 1) {
839 setAllowAnimation(mDarkAmount == 0);
840 }
841 }
842
Selim Cinek13859052017-10-05 17:12:18 -0700843 /**
844 * This method returns the drawing rect for the view which is different from the regular
845 * drawing rect, since we layout all children at position 0 and usually the translation is
846 * neglected. The standard implementation doesn't account for translation.
847 *
848 * @param outRect The (scrolled) drawing bounds of the view.
849 */
850 @Override
851 public void getDrawingRect(Rect outRect) {
852 super.getDrawingRect(outRect);
853 float translationX = getTranslationX();
854 float translationY = getTranslationY();
855 outRect.left += translationX;
856 outRect.right += translationX;
857 outRect.top += translationY;
858 outRect.bottom += translationY;
859 }
860
Selim Cinekd95ca7c2017-07-26 12:20:38 -0700861 public void setIsInShelf(boolean isInShelf) {
862 mIsInShelf = isInShelf;
863 }
864
865 public boolean isInShelf() {
866 return mIsInShelf;
867 }
868
Selim Cinek887da3c2017-10-06 13:37:32 -0700869 @Override
870 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
871 super.onLayout(changed, left, top, right, bottom);
872 if (mLayoutRunnable != null) {
873 mLayoutRunnable.run();
874 mLayoutRunnable = null;
875 }
Selim Cinek3ddda6d2018-06-08 00:26:48 -0700876 updatePivot();
877 }
878
879 private void updatePivot() {
880 setPivotX((1 - mIconScale) / 2.0f * getWidth());
881 setPivotY((getHeight() - mIconScale * getWidth()) / 2.0f);
Selim Cinek887da3c2017-10-06 13:37:32 -0700882 }
883
884 public void executeOnLayout(Runnable runnable) {
885 mLayoutRunnable = runnable;
886 }
887
Selim Cinekd03518c2018-03-15 12:13:51 -0700888 public void setDismissed() {
889 mDismissed = true;
890 if (mOnDismissListener != null) {
891 mOnDismissListener.run();
892 }
893 }
894
895 public boolean isDismissed() {
896 return mDismissed;
897 }
898
899 public void setOnDismissListener(Runnable onDismissListener) {
900 mOnDismissListener = onDismissListener;
901 }
902
Evan Lairde1d13c92018-03-20 16:58:01 -0400903 @Override
904 public void onDarkChanged(Rect area, float darkIntensity, int tint) {
Evan Laird20b87bf2018-04-12 09:54:11 -0400905 int areaTint = getTint(area, this, tint);
906 ColorStateList color = ColorStateList.valueOf(areaTint);
907 setImageTintList(color);
908 setDecorColor(areaTint);
Evan Lairde1d13c92018-03-20 16:58:01 -0400909 }
910
911 @Override
912 public boolean isIconVisible() {
913 return mIcon != null && mIcon.visible;
914 }
915
916 @Override
917 public boolean isIconBlocked() {
918 return mBlocked;
919 }
920
Selim Cinek2b549f42016-11-22 16:38:51 -0800921 public interface OnVisibilityChangedListener {
922 void onVisibilityChanged(int newVisibility);
923 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700924}