blob: 6283148c84f8cf023b41d07210a78b5f9358c024 [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
Selim Cinek49014f82016-11-04 14:55:30 -070019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ObjectAnimator;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070022import android.app.Notification;
Joe Onorato0cbda992010-05-02 16:28:15 -070023import android.content.Context;
Adrian Roosa8e18ef2016-05-26 17:17:02 -070024import android.content.pm.ApplicationInfo;
Selim Cinek3e7592d2016-04-11 09:35:54 +080025import android.content.res.Configuration;
Joe Onorato0cbda992010-05-02 16:28:15 -070026import android.content.res.Resources;
Joe Onorato0cbda992010-05-02 16:28:15 -070027import android.graphics.Canvas;
Joe Onorato6c01a112010-10-04 17:38:47 -040028import android.graphics.Paint;
29import android.graphics.Rect;
John Spurlockde84f0e2013-06-12 12:41:00 -040030import android.graphics.drawable.Drawable;
Dan Sandlerd63f9322015-05-06 15:18:49 -040031import android.graphics.drawable.Icon;
Adrian Roosa8e18ef2016-05-26 17:17:02 -070032import android.os.Parcelable;
Jeff Sharkeyded653b2012-09-27 19:09:24 -070033import android.os.UserHandle;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070034import android.text.TextUtils;
Daniel Sandler05e24142011-11-10 11:56:49 -050035import android.util.AttributeSet;
Selim Cinek49014f82016-11-04 14:55:30 -070036import android.util.FloatProperty;
Joe Onoratof9ec03c2010-09-23 15:09:18 -070037import android.util.Log;
Selim Cinek49014f82016-11-04 14:55:30 -070038import android.util.Property;
Anthony Chen55e8e1e2016-01-08 10:31:46 -080039import android.util.TypedValue;
Selim Cinek2b549f42016-11-22 16:38:51 -080040import android.view.View;
Joe Onorato0cbda992010-05-02 16:28:15 -070041import android.view.ViewDebug;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070042import android.view.accessibility.AccessibilityEvent;
Selim Cinek49014f82016-11-04 14:55:30 -070043import android.view.animation.Interpolator;
Winsonc0d70582016-01-29 10:24:39 -080044
Joe Onorato0cbda992010-05-02 16:28:15 -070045import com.android.internal.statusbar.StatusBarIcon;
Selim Cinek49014f82016-11-04 14:55:30 -070046import com.android.systemui.Interpolators;
Joe Onorato6c01a112010-10-04 17:38:47 -040047import com.android.systemui.R;
Selim Cinek49014f82016-11-04 14:55:30 -070048import com.android.systemui.statusbar.notification.NotificationUtils;
Joe Onorato6c01a112010-10-04 17:38:47 -040049
John Spurlockde84f0e2013-06-12 12:41:00 -040050import java.text.NumberFormat;
51
Joe Onorato0cbda992010-05-02 16:28:15 -070052public class StatusBarIconView extends AnimatedImageView {
Selim Cinek49014f82016-11-04 14:55:30 -070053 public static final int STATE_ICON = 0;
54 public static final int STATE_DOT = 1;
55 public static final int STATE_HIDDEN = 2;
Joe Onorato0cbda992010-05-02 16:28:15 -070056
Selim Cinek49014f82016-11-04 14:55:30 -070057 private static final String TAG = "StatusBarIconView";
58 private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
59 = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
60
61 @Override
62 public void setValue(StatusBarIconView object, float value) {
63 object.setIconAppearAmount(value);
64 }
65
66 @Override
67 public Float get(StatusBarIconView object) {
68 return object.getIconAppearAmount();
69 }
70 };
Selim Cinek5b5beb012016-11-08 18:11:58 -080071 private static final Property<StatusBarIconView, Float> DOT_APPEAR_AMOUNT
Selim Cinek49014f82016-11-04 14:55:30 -070072 = new FloatProperty<StatusBarIconView>("dot_appear_amount") {
73
74 @Override
75 public void setValue(StatusBarIconView object, float value) {
76 object.setDotAppearAmount(value);
77 }
78
79 @Override
80 public Float get(StatusBarIconView object) {
81 return object.getDotAppearAmount();
82 }
83 };
84
85 private boolean mAlwaysScaleIcon;
Joe Onorato0cbda992010-05-02 16:28:15 -070086 private StatusBarIcon mIcon;
87 @ViewDebug.ExportedProperty private String mSlot;
Joe Onorato6c01a112010-10-04 17:38:47 -040088 private Drawable mNumberBackground;
89 private Paint mNumberPain;
90 private int mNumberX;
91 private int mNumberY;
92 private String mNumberText;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070093 private Notification mNotification;
Jason Monk3b230072015-05-29 11:11:29 -040094 private final boolean mBlocked;
Selim Cinek3e7592d2016-04-11 09:35:54 +080095 private int mDensity;
Selim Cinek281c2022016-10-13 19:14:43 -070096 private float mIconScale = 1.0f;
Selim Cinek49014f82016-11-04 14:55:30 -070097 private final Paint mDotPaint = new Paint();
98 private boolean mDotVisible;
99 private float mDotRadius;
100 private int mStaticDotRadius;
101 private int mVisibleState = STATE_ICON;
102 private float mIconAppearAmount = 1.0f;
103 private ObjectAnimator mIconAppearAnimator;
104 private ObjectAnimator mDotAnimator;
105 private float mDotAppearAmount;
Selim Cinek2b549f42016-11-22 16:38:51 -0800106 private OnVisibilityChangedListener mOnVisibilityChangedListener;
Joe Onorato0cbda992010-05-02 16:28:15 -0700107
John Spurlocke6f0a712013-09-03 16:23:49 -0400108 public StatusBarIconView(Context context, String slot, Notification notification) {
Jason Monk3b230072015-05-29 11:11:29 -0400109 this(context, slot, notification, false);
110 }
111
112 public StatusBarIconView(Context context, String slot, Notification notification,
113 boolean blocked) {
Joe Onorato0cbda992010-05-02 16:28:15 -0700114 super(context);
Jason Monk3b230072015-05-29 11:11:29 -0400115 mBlocked = blocked;
Joe Onorato0cbda992010-05-02 16:28:15 -0700116 mSlot = slot;
Joe Onorato6c01a112010-10-04 17:38:47 -0400117 mNumberPain = new Paint();
118 mNumberPain.setTextAlign(Paint.Align.CENTER);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700119 mNumberPain.setColor(context.getColor(R.drawable.notification_number_text_color));
Joe Onorato6c01a112010-10-04 17:38:47 -0400120 mNumberPain.setAntiAlias(true);
Christoph Studera0506e72014-07-31 20:27:39 +0200121 setNotification(notification);
Selim Cinek3e7592d2016-04-11 09:35:54 +0800122 maybeUpdateIconScale();
123 setScaleType(ScaleType.CENTER);
124 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Selim Cinek49014f82016-11-04 14:55:30 -0700125 if (mNotification != null) {
126 setIconTint(getContext().getColor(
127 com.android.internal.R.color.notification_icon_default_color));
128 }
129 reloadDimens();
Selim Cinek3e7592d2016-04-11 09:35:54 +0800130 }
Daniel Sandler26c84b12011-07-27 00:09:40 -0400131
Selim Cinek3e7592d2016-04-11 09:35:54 +0800132 private void maybeUpdateIconScale() {
Daniel Sandler7579bca2011-08-18 15:47:26 -0400133 // We do not resize and scale system icons (on the right), only notification icons (on the
134 // left).
Selim Cinek3e7592d2016-04-11 09:35:54 +0800135 if (mNotification != null || mAlwaysScaleIcon) {
136 updateIconScale();
Daniel Sandler7579bca2011-08-18 15:47:26 -0400137 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800138 }
Daniel Sandlerabff0322011-09-27 11:19:34 -0400139
Selim Cinek3e7592d2016-04-11 09:35:54 +0800140 private void updateIconScale() {
141 Resources res = mContext.getResources();
142 final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
143 final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
Selim Cinek281c2022016-10-13 19:14:43 -0700144 mIconScale = (float)imageBounds / (float)outerBounds;
Selim Cinek281c2022016-10-13 19:14:43 -0700145 }
146
147 public float getIconScale() {
148 return mIconScale;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800149 }
150
151 @Override
152 protected void onConfigurationChanged(Configuration newConfig) {
153 super.onConfigurationChanged(newConfig);
154 int density = newConfig.densityDpi;
155 if (density != mDensity) {
156 mDensity = density;
157 maybeUpdateIconScale();
158 updateDrawable();
Selim Cinek49014f82016-11-04 14:55:30 -0700159 reloadDimens();
160 }
161 }
162
163 private void reloadDimens() {
164 boolean applyRadius = mDotRadius == mStaticDotRadius;
165 mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
166 if (applyRadius) {
167 mDotRadius = mStaticDotRadius;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800168 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700169 }
170
Christoph Studera0506e72014-07-31 20:27:39 +0200171 public void setNotification(Notification notification) {
172 mNotification = notification;
173 setContentDescription(notification);
174 }
175
Daniel Sandler05e24142011-11-10 11:56:49 -0500176 public StatusBarIconView(Context context, AttributeSet attrs) {
177 super(context, attrs);
Jason Monk3b230072015-05-29 11:11:29 -0400178 mBlocked = false;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800179 mAlwaysScaleIcon = true;
180 updateIconScale();
181 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Daniel Sandler05e24142011-11-10 11:56:49 -0500182 }
183
Joe Onorato0cbda992010-05-02 16:28:15 -0700184 private static boolean streq(String a, String b) {
Joe Onorato66d7d012010-05-14 10:05:10 -0700185 if (a == b) {
186 return true;
187 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700188 if (a == null && b != null) {
189 return false;
190 }
191 if (a != null && b == null) {
192 return false;
193 }
194 return a.equals(b);
195 }
196
Dan Sandlerd63f9322015-05-06 15:18:49 -0400197 public boolean equalIcons(Icon a, Icon b) {
198 if (a == b) return true;
199 if (a.getType() != b.getType()) return false;
200 switch (a.getType()) {
201 case Icon.TYPE_RESOURCE:
202 return a.getResPackage().equals(b.getResPackage()) && a.getResId() == b.getResId();
203 case Icon.TYPE_URI:
204 return a.getUriString().equals(b.getUriString());
205 default:
206 return false;
207 }
208 }
Joe Onorato005847b2010-06-04 16:08:02 -0400209 /**
210 * Returns whether the set succeeded.
211 */
212 public boolean set(StatusBarIcon icon) {
Dan Sandlerd63f9322015-05-06 15:18:49 -0400213 final boolean iconEquals = mIcon != null && equalIcons(mIcon.icon, icon.icon);
Joe Onorato005847b2010-06-04 16:08:02 -0400214 final boolean levelEquals = iconEquals
215 && mIcon.iconLevel == icon.iconLevel;
216 final boolean visibilityEquals = mIcon != null
217 && mIcon.visible == icon.visible;
Joe Onorato6c01a112010-10-04 17:38:47 -0400218 final boolean numberEquals = mIcon != null
219 && mIcon.number == icon.number;
220 mIcon = icon.clone();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700221 setContentDescription(icon.contentDescription);
Joe Onorato005847b2010-06-04 16:08:02 -0400222 if (!iconEquals) {
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800223 if (!updateDrawable(false /* no clear */)) return false;
Selim Cinek2b6eb8032016-12-29 14:22:21 +0100224 // we have to clear the grayscale tag since it may have changed
225 setTag(R.id.icon_is_grayscale, null);
Joe Onorato0cbda992010-05-02 16:28:15 -0700226 }
Joe Onorato005847b2010-06-04 16:08:02 -0400227 if (!levelEquals) {
228 setImageLevel(icon.iconLevel);
Joe Onorato0cbda992010-05-02 16:28:15 -0700229 }
Daniel Sandler26c84b12011-07-27 00:09:40 -0400230
Joe Onorato6c01a112010-10-04 17:38:47 -0400231 if (!numberEquals) {
John Spurlock01534782014-01-13 11:59:22 -0500232 if (icon.number > 0 && getContext().getResources().getBoolean(
Joe Onorato8595a3d2010-11-19 18:12:07 -0800233 R.bool.config_statusBarShowNumber)) {
Joe Onorato6c01a112010-10-04 17:38:47 -0400234 if (mNumberBackground == null) {
235 mNumberBackground = getContext().getResources().getDrawable(
236 R.drawable.ic_notification_overlay);
237 }
238 placeNumber();
239 } else {
240 mNumberBackground = null;
241 mNumberText = null;
242 }
243 invalidate();
244 }
Joe Onorato005847b2010-06-04 16:08:02 -0400245 if (!visibilityEquals) {
Jason Monk3b230072015-05-29 11:11:29 -0400246 setVisibility(icon.visible && !mBlocked ? VISIBLE : GONE);
Joe Onorato005847b2010-06-04 16:08:02 -0400247 }
Joe Onorato005847b2010-06-04 16:08:02 -0400248 return true;
Joe Onorato0cbda992010-05-02 16:28:15 -0700249 }
250
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800251 public void updateDrawable() {
252 updateDrawable(true /* with clear */);
253 }
254
255 private boolean updateDrawable(boolean withClear) {
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100256 if (mIcon == null) {
257 return false;
258 }
Adrian Roosfb2d0cc2017-01-31 15:10:00 -0800259 Drawable drawable;
260 try {
261 drawable = getIcon(mIcon);
262 } catch (OutOfMemoryError e) {
263 Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
264 return false;
265 }
266
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800267 if (drawable == null) {
Adrian Roosfb2d0cc2017-01-31 15:10:00 -0800268 Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800269 return false;
270 }
271 if (withClear) {
272 setImageDrawable(null);
273 }
274 setImageDrawable(drawable);
275 return true;
276 }
277
Joe Onoratof5510542010-06-01 07:46:41 -0700278 private Drawable getIcon(StatusBarIcon icon) {
279 return getIcon(getContext(), icon);
280 }
281
Joe Onorato0cbda992010-05-02 16:28:15 -0700282 /**
Dan Sandlerd63f9322015-05-06 15:18:49 -0400283 * Returns the right icon to use for this item
John Spurlock209bede2013-07-17 12:23:27 -0400284 *
Dan Sandlerd63f9322015-05-06 15:18:49 -0400285 * @param context Context to use to get resources
Joe Onorato0cbda992010-05-02 16:28:15 -0700286 * @return Drawable for this item, or null if the package or item could not
287 * be found
288 */
Anthony Chen55e8e1e2016-01-08 10:31:46 -0800289 public static Drawable getIcon(Context context, StatusBarIcon statusBarIcon) {
290 int userId = statusBarIcon.user.getIdentifier();
Dan Sandlerd63f9322015-05-06 15:18:49 -0400291 if (userId == UserHandle.USER_ALL) {
Xiaohui Chen87d0e252015-07-30 15:38:16 -0700292 userId = UserHandle.USER_SYSTEM;
Joe Onorato0cbda992010-05-02 16:28:15 -0700293 }
Anthony Chen55e8e1e2016-01-08 10:31:46 -0800294
295 Drawable icon = statusBarIcon.icon.loadDrawableAsUser(context, userId);
296
297 TypedValue typedValue = new TypedValue();
298 context.getResources().getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
299 float scaleFactor = typedValue.getFloat();
300
301 // No need to scale the icon, so return it as is.
302 if (scaleFactor == 1.f) {
303 return icon;
304 }
305
306 return new ScalingDrawableWrapper(icon, scaleFactor);
Joe Onorato0cbda992010-05-02 16:28:15 -0700307 }
Joe Onoratob77f53b2010-05-28 19:59:51 -0400308
309 public StatusBarIcon getStatusBarIcon() {
310 return mIcon;
311 }
Joe Onoratof9ec03c2010-09-23 15:09:18 -0700312
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700313 @Override
314 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
315 super.onInitializeAccessibilityEvent(event);
316 if (mNotification != null) {
317 event.setParcelableData(mNotification);
318 }
319 }
320
321 @Override
Joe Onorato6c01a112010-10-04 17:38:47 -0400322 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
323 super.onSizeChanged(w, h, oldw, oldh);
324 if (mNumberBackground != null) {
325 placeNumber();
326 }
327 }
328
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700329 @Override
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100330 public void onRtlPropertiesChanged(int layoutDirection) {
331 super.onRtlPropertiesChanged(layoutDirection);
332 updateDrawable();
333 }
334
335 @Override
Joe Onorato6c01a112010-10-04 17:38:47 -0400336 protected void onDraw(Canvas canvas) {
Selim Cinek49014f82016-11-04 14:55:30 -0700337 if (mIconAppearAmount > 0.0f) {
338 canvas.save();
339 canvas.scale(mIconScale * mIconAppearAmount, mIconScale * mIconAppearAmount,
340 getWidth() / 2, getHeight() / 2);
341 super.onDraw(canvas);
342 canvas.restore();
343 }
Joe Onorato6c01a112010-10-04 17:38:47 -0400344
345 if (mNumberBackground != null) {
346 mNumberBackground.draw(canvas);
347 canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain);
348 }
Selim Cinek49014f82016-11-04 14:55:30 -0700349 if (mDotAppearAmount != 0.0f) {
350 float radius;
351 float alpha;
352 if (mDotAppearAmount <= 1.0f) {
353 radius = mDotRadius * mDotAppearAmount;
354 alpha = 1.0f;
355 } else {
356 float fadeOutAmount = mDotAppearAmount - 1.0f;
357 alpha = 1.0f - fadeOutAmount;
358 radius = NotificationUtils.interpolate(mDotRadius, getWidth() / 4, fadeOutAmount);
359 }
360 mDotPaint.setAlpha((int) (alpha * 255));
361 canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mDotPaint);
362 }
Joe Onorato6c01a112010-10-04 17:38:47 -0400363 }
364
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700365 @Override
Joe Onoratof9ec03c2010-09-23 15:09:18 -0700366 protected void debug(int depth) {
367 super.debug(depth);
368 Log.d("View", debugIndent(depth) + "slot=" + mSlot);
369 Log.d("View", debugIndent(depth) + "icon=" + mIcon);
370 }
Joe Onorato6c01a112010-10-04 17:38:47 -0400371
372 void placeNumber() {
Daniel Sandlerebce0112011-06-16 16:44:51 -0400373 final String str;
John Spurlock01534782014-01-13 11:59:22 -0500374 final int tooBig = getContext().getResources().getInteger(
Daniel Sandlerebce0112011-06-16 16:44:51 -0400375 android.R.integer.status_bar_notification_info_maxnum);
376 if (mIcon.number > tooBig) {
John Spurlock01534782014-01-13 11:59:22 -0500377 str = getContext().getResources().getString(
Daniel Sandlerebce0112011-06-16 16:44:51 -0400378 android.R.string.status_bar_notification_info_overflow);
379 } else {
380 NumberFormat f = NumberFormat.getIntegerInstance();
381 str = f.format(mIcon.number);
382 }
383 mNumberText = str;
384
Joe Onorato6c01a112010-10-04 17:38:47 -0400385 final int w = getWidth();
386 final int h = getHeight();
387 final Rect r = new Rect();
388 mNumberPain.getTextBounds(str, 0, str.length(), r);
389 final int tw = r.right - r.left;
390 final int th = r.bottom - r.top;
391 mNumberBackground.getPadding(r);
392 int dw = r.left + tw + r.right;
393 if (dw < mNumberBackground.getMinimumWidth()) {
394 dw = mNumberBackground.getMinimumWidth();
395 }
396 mNumberX = w-r.right-((dw-r.right-r.left)/2);
397 int dh = r.top + th + r.bottom;
398 if (dh < mNumberBackground.getMinimumWidth()) {
399 dh = mNumberBackground.getMinimumWidth();
400 }
401 mNumberY = h-r.bottom-((dh-r.top-th-r.bottom)/2);
402 mNumberBackground.setBounds(w-dw, h-dh, w, h);
403 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700404
405 private void setContentDescription(Notification notification) {
406 if (notification != null) {
Adrian Rooseba05822016-04-22 17:09:27 -0700407 String d = contentDescForNotification(mContext, notification);
408 if (!TextUtils.isEmpty(d)) {
409 setContentDescription(d);
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700410 }
411 }
412 }
Daniel Sandler7579bca2011-08-18 15:47:26 -0400413
414 public String toString() {
John Spurlock209bede2013-07-17 12:23:27 -0400415 return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon
Daniel Sandler7579bca2011-08-18 15:47:26 -0400416 + " notification=" + mNotification + ")";
417 }
Jason Monk3b230072015-05-29 11:11:29 -0400418
419 public String getSlot() {
420 return mSlot;
421 }
Adrian Rooseba05822016-04-22 17:09:27 -0700422
423
424 public static String contentDescForNotification(Context c, Notification n) {
Adrian Roosa8e18ef2016-05-26 17:17:02 -0700425 String appName = "";
426 try {
427 Notification.Builder builder = Notification.Builder.recoverBuilder(c, n);
428 appName = builder.loadHeaderAppName();
429 } catch (RuntimeException e) {
430 Log.e(TAG, "Unable to recover builder", e);
431 // Trying to get the app name from the app info instead.
432 Parcelable appInfo = n.extras.getParcelable(
433 Notification.EXTRA_BUILDER_APPLICATION_INFO);
434 if (appInfo instanceof ApplicationInfo) {
435 appName = String.valueOf(((ApplicationInfo) appInfo).loadLabel(
436 c.getPackageManager()));
437 }
438 }
Adrian Roos51548e62016-04-28 11:20:26 -0700439
Julia Reynolds7f9ce782016-05-17 15:34:34 -0400440 CharSequence title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
Adrian Rooseba05822016-04-22 17:09:27 -0700441 CharSequence ticker = n.tickerText;
Adrian Roos51548e62016-04-28 11:20:26 -0700442
443 CharSequence desc = !TextUtils.isEmpty(ticker) ? ticker
444 : !TextUtils.isEmpty(title) ? title : "";
445
446 return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
Adrian Rooseba05822016-04-22 17:09:27 -0700447 }
Adrian Roos51548e62016-04-28 11:20:26 -0700448
Selim Cinek49014f82016-11-04 14:55:30 -0700449 public void setIconTint(int iconTint) {
450 mDotPaint.setColor(iconTint);
451 }
452
Selim Cinek5b5beb012016-11-08 18:11:58 -0800453 public void setVisibleState(int state) {
454 setVisibleState(state, true /* animate */, null /* endRunnable */);
455 }
456
457 public void setVisibleState(int state, boolean animate) {
458 setVisibleState(state, animate, null);
459 }
460
461 @Override
462 public boolean hasOverlappingRendering() {
463 return false;
464 }
465
466 public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) {
Selim Cinek65d418e2016-11-29 15:42:34 -0800467 boolean runnableAdded = false;
Selim Cinek49014f82016-11-04 14:55:30 -0700468 if (visibleState != mVisibleState) {
469 mVisibleState = visibleState;
Selim Cinek5b5beb012016-11-08 18:11:58 -0800470 if (animate) {
471 if (mIconAppearAnimator != null) {
472 mIconAppearAnimator.cancel();
Selim Cinek49014f82016-11-04 14:55:30 -0700473 }
Selim Cinek5b5beb012016-11-08 18:11:58 -0800474 float targetAmount = 0.0f;
475 Interpolator interpolator = Interpolators.FAST_OUT_LINEAR_IN;
476 if (visibleState == STATE_ICON) {
477 targetAmount = 1.0f;
478 interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
479 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800480 float currentAmount = getIconAppearAmount();
481 if (targetAmount != currentAmount) {
482 mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
483 currentAmount, targetAmount);
484 mIconAppearAnimator.setInterpolator(interpolator);
485 mIconAppearAnimator.setDuration(100);
486 mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
487 @Override
488 public void onAnimationEnd(Animator animation) {
489 mIconAppearAnimator = null;
490 runRunnable(endRunnable);
Selim Cinek5b5beb012016-11-08 18:11:58 -0800491 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800492 });
493 mIconAppearAnimator.start();
494 runnableAdded = true;
495 }
Selim Cinek49014f82016-11-04 14:55:30 -0700496
Selim Cinek5b5beb012016-11-08 18:11:58 -0800497 if (mDotAnimator != null) {
498 mDotAnimator.cancel();
Selim Cinek49014f82016-11-04 14:55:30 -0700499 }
Selim Cinek5b5beb012016-11-08 18:11:58 -0800500 targetAmount = visibleState == STATE_ICON ? 2.0f : 0.0f;
501 interpolator = Interpolators.FAST_OUT_LINEAR_IN;
502 if (visibleState == STATE_DOT) {
503 targetAmount = 1.0f;
504 interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
505 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800506 currentAmount = getDotAppearAmount();
507 if (targetAmount != currentAmount) {
508 mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
509 currentAmount, targetAmount);
510 mDotAnimator.setInterpolator(interpolator);
511 mDotAnimator.setDuration(100);
512 final boolean runRunnable = !runnableAdded;
513 mDotAnimator.addListener(new AnimatorListenerAdapter() {
514 @Override
515 public void onAnimationEnd(Animator animation) {
516 mDotAnimator = null;
517 if (runRunnable) {
518 runRunnable(endRunnable);
519 }
520 }
521 });
522 mDotAnimator.start();
523 runnableAdded = true;
524 }
Selim Cinek5b5beb012016-11-08 18:11:58 -0800525 } else {
526 setIconAppearAmount(visibleState == STATE_ICON ? 1.0f : 0.0f);
Selim Cinek01a73f92016-12-06 16:13:42 -0800527 setDotAppearAmount(visibleState == STATE_DOT ? 1.0f
528 : visibleState == STATE_ICON ? 2.0f
529 : 0.0f);
Selim Cinek5b5beb012016-11-08 18:11:58 -0800530 }
Selim Cinek49014f82016-11-04 14:55:30 -0700531 }
Selim Cinek65d418e2016-11-29 15:42:34 -0800532 if (!runnableAdded) {
533 runRunnable(endRunnable);
534 }
535 }
536
537 private void runRunnable(Runnable runnable) {
538 if (runnable != null) {
539 runnable.run();
540 }
Selim Cinek49014f82016-11-04 14:55:30 -0700541 }
542
Selim Cinek5b5beb012016-11-08 18:11:58 -0800543 public void setIconAppearAmount(float iconAppearAmount) {
Selim Cinek49014f82016-11-04 14:55:30 -0700544 mIconAppearAmount = iconAppearAmount;
545 invalidate();
546 }
547
548 public float getIconAppearAmount() {
549 return mIconAppearAmount;
550 }
551
552 public int getVisibleState() {
553 return mVisibleState;
554 }
555
556 public void setDotAppearAmount(float dotAppearAmount) {
557 mDotAppearAmount = dotAppearAmount;
558 invalidate();
559 }
560
Selim Cinek2b549f42016-11-22 16:38:51 -0800561 @Override
562 public void setVisibility(int visibility) {
563 super.setVisibility(visibility);
564 if (mOnVisibilityChangedListener != null) {
565 mOnVisibilityChangedListener.onVisibilityChanged(visibility);
566 }
567 }
568
Selim Cinek49014f82016-11-04 14:55:30 -0700569 public float getDotAppearAmount() {
570 return mDotAppearAmount;
571 }
Selim Cinek2b549f42016-11-22 16:38:51 -0800572
573 public void setOnVisibilityChangedListener(OnVisibilityChangedListener listener) {
574 mOnVisibilityChangedListener = listener;
575 }
576
577 public interface OnVisibilityChangedListener {
578 void onVisibilityChanged(int newVisibility);
579 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700580}