blob: 1a3560ece1d7faf4b9e3ea69d78332483c0fa3c9 [file] [log] [blame]
Anthony Chen83092c62016-01-11 17:00:36 -08001package com.android.systemui.statusbar.phone;
2
3import android.content.Context;
Anthony Chen83092c62016-01-11 17:00:36 -08004import android.content.res.Resources;
5import android.graphics.Color;
Jorim Jaggi86905582016-02-09 21:36:09 -08006import android.graphics.Rect;
Anthony Chen83092c62016-01-11 17:00:36 -08007import android.view.LayoutInflater;
8import android.view.View;
Jason Monke59dc402018-08-16 12:05:01 -04009import android.view.ViewGroup;
Selim Cinek0e8d77e2016-11-29 10:35:42 -080010import android.widget.FrameLayout;
Winsonc0d70582016-01-29 10:24:39 -080011
Beverly8fdb5332019-02-04 14:29:49 -050012import androidx.annotation.NonNull;
13import androidx.collection.ArrayMap;
14
Selim Cinek72fc8db2017-06-06 18:07:47 -070015import com.android.internal.statusbar.StatusBarIcon;
Lucas Dupina291d192018-06-07 13:59:42 -070016import com.android.internal.util.ContrastColorUtil;
Selim Cinek195dfc52019-05-30 19:35:05 -070017import com.android.settingslib.Utils;
Selim Cinekd03518c2018-03-15 12:13:51 -070018import com.android.systemui.Dependency;
Selim Cinek195dfc52019-05-30 19:35:05 -070019import com.android.systemui.Interpolators;
Anthony Chen83092c62016-01-11 17:00:36 -080020import com.android.systemui.R;
Beverly1be62f42018-12-19 17:17:48 -050021import com.android.systemui.plugins.DarkIconDispatcher;
22import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
Beverly8fdb5332019-02-04 14:29:49 -050023import com.android.systemui.plugins.statusbar.StatusBarStateController;
Selim Cinek999230c2019-06-19 15:36:44 -070024import com.android.systemui.statusbar.CrossFadeHelper;
Lucas Dupin20403372019-02-14 19:59:18 -080025import com.android.systemui.statusbar.NotificationMediaManager;
Selim Cinek281c2022016-10-13 19:14:43 -070026import com.android.systemui.statusbar.NotificationShelf;
Anthony Chen83092c62016-01-11 17:00:36 -080027import com.android.systemui.statusbar.StatusBarIconView;
Selim Cinek195dfc52019-05-30 19:35:05 -070028import com.android.systemui.statusbar.StatusBarState;
Gus Prevas33619af2018-10-26 15:40:27 -040029import com.android.systemui.statusbar.notification.NotificationEntryManager;
Anthony Chen83092c62016-01-11 17:00:36 -080030import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cinek820ba2d2019-06-18 18:59:09 -070031import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
Ned Burnsf81c4c42019-01-07 14:10:43 -050032import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Gus Prevas33619af2018-10-26 15:40:27 -040033import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Anthony Chen83092c62016-01-11 17:00:36 -080034
35import java.util.ArrayList;
Beverly40770652019-02-15 15:49:49 -050036import java.util.Objects;
Selim Cinek281c2022016-10-13 19:14:43 -070037import java.util.function.Function;
Anthony Chen83092c62016-01-11 17:00:36 -080038
39/**
40 * A controller for the space in the status bar to the left of the system icons. This area is
41 * normally reserved for notifications.
42 */
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080043public class NotificationIconAreaController implements DarkReceiver,
Selim Cinek820ba2d2019-06-18 18:59:09 -070044 StatusBarStateController.StateListener,
45 NotificationWakeUpCoordinator.WakeUpListener {
Gus Prevas33619af2018-10-26 15:40:27 -040046
Selim Cinekda330ff2019-06-11 15:41:28 -070047 public static final String HIGH_PRIORITY = "high_priority";
Selim Cinek195dfc52019-05-30 19:35:05 -070048 private static final long AOD_ICONS_APPEAR_DURATION = 200;
Gus Prevas33619af2018-10-26 15:40:27 -040049
Lucas Dupina291d192018-06-07 13:59:42 -070050 private final ContrastColorUtil mContrastColorUtil;
Selim Cinekd03518c2018-03-15 12:13:51 -070051 private final NotificationEntryManager mEntryManager;
52 private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080053 private final StatusBarStateController mStatusBarStateController;
Lucas Dupin20403372019-02-14 19:59:18 -080054 private final NotificationMediaManager mMediaManager;
Selim Cinek820ba2d2019-06-18 18:59:09 -070055 private final NotificationWakeUpCoordinator mWakeUpCoordinator;
56 private final KeyguardBypassController mBypassController;
Selim Cinek195dfc52019-05-30 19:35:05 -070057 private final DozeParameters mDozeParameters;
Anthony Chen83092c62016-01-11 17:00:36 -080058
59 private int mIconSize;
60 private int mIconHPadding;
61 private int mIconTint = Color.WHITE;
Beverly40770652019-02-15 15:49:49 -050062 private int mCenteredIconTint = Color.WHITE;
Anthony Chen83092c62016-01-11 17:00:36 -080063
Jason Monk2a6ea9c2017-01-26 11:14:51 -050064 private StatusBar mStatusBar;
Anthony Chen83092c62016-01-11 17:00:36 -080065 protected View mNotificationIconArea;
Selim Cinek281c2022016-10-13 19:14:43 -070066 private NotificationIconContainer mNotificationIcons;
Selim Cinek5b5beb012016-11-08 18:11:58 -080067 private NotificationIconContainer mShelfIcons;
Beverly40770652019-02-15 15:49:49 -050068 protected View mCenteredIconArea;
69 private NotificationIconContainer mCenteredIcon;
Selim Cinek195dfc52019-05-30 19:35:05 -070070 private NotificationIconContainer mAodIcons;
Beverly40770652019-02-15 15:49:49 -050071 private StatusBarIconView mCenteredIconView;
Jorim Jaggi86905582016-02-09 21:36:09 -080072 private final Rect mTintArea = new Rect();
Jason Monke59dc402018-08-16 12:05:01 -040073 private ViewGroup mNotificationScrollLayout;
Selim Cinek281c2022016-10-13 19:14:43 -070074 private Context mContext;
Selim Cinek195dfc52019-05-30 19:35:05 -070075 private int mAodIconAppearTranslation;
Anthony Chen83092c62016-01-11 17:00:36 -080076
Selim Cinek195dfc52019-05-30 19:35:05 -070077 private boolean mAnimationsEnabled;
78 private int mAodIconTint;
79 private boolean mFullyHidden;
Selim Cinek999230c2019-06-19 15:36:44 -070080 private boolean mAodIconsVisible;
Selim Cinek65c96f22019-07-25 20:09:04 -070081 private boolean mIsPulsing;
Lucas Dupin23a8d3b2018-10-08 20:57:35 -070082
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080083 public NotificationIconAreaController(Context context, StatusBar statusBar,
Julia Reynolds12ad7ca2019-01-28 09:29:16 -050084 StatusBarStateController statusBarStateController,
Selim Cinek820ba2d2019-06-18 18:59:09 -070085 NotificationWakeUpCoordinator wakeUpCoordinator,
86 KeyguardBypassController keyguardBypassController,
Lucas Dupin20403372019-02-14 19:59:18 -080087 NotificationMediaManager notificationMediaManager) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -050088 mStatusBar = statusBar;
Lucas Dupina291d192018-06-07 13:59:42 -070089 mContrastColorUtil = ContrastColorUtil.getInstance(context);
Selim Cinek281c2022016-10-13 19:14:43 -070090 mContext = context;
Selim Cinekd03518c2018-03-15 12:13:51 -070091 mEntryManager = Dependency.get(NotificationEntryManager.class);
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080092 mStatusBarStateController = statusBarStateController;
93 mStatusBarStateController.addCallback(this);
Lucas Dupin20403372019-02-14 19:59:18 -080094 mMediaManager = notificationMediaManager;
Selim Cinek195dfc52019-05-30 19:35:05 -070095 mDozeParameters = DozeParameters.getInstance(mContext);
Selim Cinek820ba2d2019-06-18 18:59:09 -070096 mWakeUpCoordinator = wakeUpCoordinator;
97 wakeUpCoordinator.addListener(this);
98 mBypassController = keyguardBypassController;
Gus Prevas33619af2018-10-26 15:40:27 -040099
Anthony Chen83092c62016-01-11 17:00:36 -0800100 initializeNotificationAreaViews(context);
Selim Cinek195dfc52019-05-30 19:35:05 -0700101 reloadAodColor();
Anthony Chen83092c62016-01-11 17:00:36 -0800102 }
103
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700104 protected View inflateIconArea(LayoutInflater inflater) {
105 return inflater.inflate(R.layout.notification_icon_area, null);
106 }
107
Anthony Chen83092c62016-01-11 17:00:36 -0800108 /**
109 * Initializes the views that will represent the notification area.
110 */
111 protected void initializeNotificationAreaViews(Context context) {
Selim Cinek3e7592d2016-04-11 09:35:54 +0800112 reloadDimens(context);
Anthony Chen83092c62016-01-11 17:00:36 -0800113
114 LayoutInflater layoutInflater = LayoutInflater.from(context);
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700115 mNotificationIconArea = inflateIconArea(layoutInflater);
Jason Monke59dc402018-08-16 12:05:01 -0400116 mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);
Anthony Chen83092c62016-01-11 17:00:36 -0800117
Jason Monkaa573e92017-01-27 17:00:29 -0500118 mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
Beverly40770652019-02-15 15:49:49 -0500119
120 mCenteredIconArea = layoutInflater.inflate(R.layout.center_icon_area, null);
121 mCenteredIcon = mCenteredIconArea.findViewById(R.id.centeredIcon);
Selim Cinek195dfc52019-05-30 19:35:05 -0700122
123 initAodIcons();
124 }
125
126 public void initAodIcons() {
127 boolean changed = mAodIcons != null;
128 if (changed) {
129 mAodIcons.setAnimationsEnabled(false);
130 mAodIcons.removeAllViews();
131 }
132 mAodIcons = mStatusBar.getStatusBarWindow().findViewById(
133 R.id.clock_notification_icon_container);
134 mAodIcons.setOnLockScreen(true);
Selim Cinek999230c2019-06-19 15:36:44 -0700135 updateAodIconsVisibility(false /* animate */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700136 updateAnimations();
137 if (changed) {
Selim Cinek999230c2019-06-19 15:36:44 -0700138 updateAodNotificationIcons();
Selim Cinek195dfc52019-05-30 19:35:05 -0700139 }
Jason Monkaa573e92017-01-27 17:00:29 -0500140 }
141
142 public void setupShelf(NotificationShelf shelf) {
Selim Cinek5b5beb012016-11-08 18:11:58 -0800143 mShelfIcons = shelf.getShelfIcons();
Selim Cinek49014f82016-11-04 14:55:30 -0700144 shelf.setCollapsedIcons(mNotificationIcons);
Anthony Chen83092c62016-01-11 17:00:36 -0800145 }
146
Selim Cinek3e7592d2016-04-11 09:35:54 +0800147 public void onDensityOrFontScaleChanged(Context context) {
148 reloadDimens(context);
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800149 final FrameLayout.LayoutParams params = generateIconLayoutParams();
Selim Cinek3e7592d2016-04-11 09:35:54 +0800150 for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
151 View child = mNotificationIcons.getChildAt(i);
152 child.setLayoutParams(params);
Selim Cinek9ef119c2017-03-01 15:13:36 -0800153 }
154 for (int i = 0; i < mShelfIcons.getChildCount(); i++) {
155 View child = mShelfIcons.getChildAt(i);
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800156 child.setLayoutParams(params);
Selim Cinek3e7592d2016-04-11 09:35:54 +0800157 }
Beverly40770652019-02-15 15:49:49 -0500158 for (int i = 0; i < mCenteredIcon.getChildCount(); i++) {
159 View child = mCenteredIcon.getChildAt(i);
160 child.setLayoutParams(params);
161 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700162 for (int i = 0; i < mAodIcons.getChildCount(); i++) {
163 View child = mAodIcons.getChildAt(i);
164 child.setLayoutParams(params);
165 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800166 }
167
168 @NonNull
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800169 private FrameLayout.LayoutParams generateIconLayoutParams() {
170 return new FrameLayout.LayoutParams(
Selim Cinek3e7592d2016-04-11 09:35:54 +0800171 mIconSize + 2 * mIconHPadding, getHeight());
172 }
173
174 private void reloadDimens(Context context) {
175 Resources res = context.getResources();
176 mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
177 mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
Selim Cinek195dfc52019-05-30 19:35:05 -0700178 mAodIconAppearTranslation = res.getDimensionPixelSize(
179 R.dimen.shelf_appear_translation);
Selim Cinek3e7592d2016-04-11 09:35:54 +0800180 }
181
Anthony Chen83092c62016-01-11 17:00:36 -0800182 /**
183 * Returns the view that represents the notification area.
184 */
185 public View getNotificationInnerAreaView() {
186 return mNotificationIconArea;
187 }
188
189 /**
Beverly40770652019-02-15 15:49:49 -0500190 * Returns the view that represents the centered notification area.
191 */
192 public View getCenteredNotificationAreaView() {
193 return mCenteredIconArea;
194 }
195
196 /**
Jason Monkaa573e92017-01-27 17:00:29 -0500197 * See {@link com.android.systemui.statusbar.policy.DarkIconDispatcher#setIconsDarkArea}.
198 * Sets the color that should be used to tint any icons in the notification area.
Jorim Jaggi86905582016-02-09 21:36:09 -0800199 *
200 * @param tintArea the area in which to tint the icons, specified in screen coordinates
Jason Monkaa573e92017-01-27 17:00:29 -0500201 * @param darkIntensity
Jorim Jaggi86905582016-02-09 21:36:09 -0800202 */
Jason Monkaa573e92017-01-27 17:00:29 -0500203 public void onDarkChanged(Rect tintArea, float darkIntensity, int iconTint) {
Jorim Jaggi86905582016-02-09 21:36:09 -0800204 if (tintArea == null) {
205 mTintArea.setEmpty();
206 } else {
207 mTintArea.set(tintArea);
208 }
Beverly40770652019-02-15 15:49:49 -0500209
Evan Lairddbeefe32018-04-03 16:52:41 -0400210 if (mNotificationIconArea != null) {
211 if (DarkIconDispatcher.isInArea(tintArea, mNotificationIconArea)) {
212 mIconTint = iconTint;
213 }
214 } else {
215 mIconTint = iconTint;
216 }
217
Beverly40770652019-02-15 15:49:49 -0500218 if (mCenteredIconArea != null) {
219 if (DarkIconDispatcher.isInArea(tintArea, mCenteredIconArea)) {
220 mCenteredIconTint = iconTint;
221 }
222 } else {
223 mCenteredIconTint = iconTint;
224 }
225
Anthony Chen83092c62016-01-11 17:00:36 -0800226 applyNotificationIconsTint();
227 }
228
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700229 protected int getHeight() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500230 return mStatusBar.getStatusBarHeight();
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700231 }
232
Ned Burnsf81c4c42019-01-07 14:10:43 -0500233 protected boolean shouldShowNotificationIcon(NotificationEntry entry,
Selim Cinek31ebb402019-07-19 18:29:56 -0700234 boolean showAmbient, boolean hideDismissed,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700235 boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400236 boolean hidePulsing, boolean onlyShowCenteredIcon) {
Beverly40770652019-02-15 15:49:49 -0500237
Beverlyfd3b1dca2019-06-25 16:21:00 -0400238 final boolean isCenteredNotificationIcon = mCenteredIconView != null
239 && entry.centeredIcon != null
Beverly40770652019-02-15 15:49:49 -0500240 && Objects.equals(entry.centeredIcon, mCenteredIconView);
Beverlyfd3b1dca2019-06-25 16:21:00 -0400241 if (onlyShowCenteredIcon) {
242 return isCenteredNotificationIcon;
243 }
Selim Cineke3c6e462019-06-24 19:37:06 -0700244 if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
Beverly40770652019-02-15 15:49:49 -0500245 return false;
246 }
Selim Cinekd03518c2018-03-15 12:13:51 -0700247 if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700248 return false;
249 }
Lucas Dupin20403372019-02-14 19:59:18 -0800250 if (hideCurrentMedia && entry.key.equals(mMediaManager.getMediaNotificationKey())) {
251 return false;
252 }
Evan Laird94492852018-10-25 13:43:01 -0400253 if (!entry.isTopLevelChild()) {
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700254 return false;
255 }
Evan Laird94492852018-10-25 13:43:01 -0400256 if (entry.getRow().getVisibility() == View.GONE) {
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700257 return false;
258 }
Evan Laird94492852018-10-25 13:43:01 -0400259 if (entry.isRowDismissed() && hideDismissed) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700260 return false;
261 }
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700262 if (hideRepliedMessages && entry.isLastMessageFromReply()) {
263 return false;
264 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -0500265 // showAmbient == show in shade but not shelf
Selim Cinek195dfc52019-05-30 19:35:05 -0700266 if (!showAmbient && entry.shouldSuppressStatusBar()) {
Julia Reynoldsc861a3d2018-02-15 10:34:49 -0500267 return false;
268 }
Selim Cinek65c96f22019-07-25 20:09:04 -0700269 if (hidePulsing && entry.showingPulsing()
270 && (!mWakeUpCoordinator.getNotificationsFullyHidden()
271 || !entry.isPulseSuppressed())) {
Selim Cinek820ba2d2019-06-18 18:59:09 -0700272 return false;
273 }
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700274 return true;
275 }
276
Anthony Chen83092c62016-01-11 17:00:36 -0800277 /**
278 * Updates the notifications with the given list of notifications to display.
279 */
Selim Cinekd03518c2018-03-15 12:13:51 -0700280 public void updateNotificationIcons() {
Selim Cinekd03518c2018-03-15 12:13:51 -0700281 updateStatusBarIcons();
Selim Cinek9bfc7a52018-06-11 16:09:00 -0700282 updateShelfIcons();
Beverly40770652019-02-15 15:49:49 -0500283 updateCenterIcon();
Selim Cinek999230c2019-06-19 15:36:44 -0700284 updateAodNotificationIcons();
Selim Cinek281c2022016-10-13 19:14:43 -0700285
286 applyNotificationIconsTint();
Selim Cinek281c2022016-10-13 19:14:43 -0700287 }
288
Selim Cinek9bfc7a52018-06-11 16:09:00 -0700289 private void updateShelfIcons() {
290 updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
Beverly40770652019-02-15 15:49:49 -0500291 true /* showAmbient */,
Beverly40770652019-02-15 15:49:49 -0500292 false /* hideDismissed */,
Selim Cinek195dfc52019-05-30 19:35:05 -0700293 false /* hideRepliedMessages */,
294 false /* hideCurrentMedia */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400295 false /* hide centered icon */,
296 false /* hidePulsing */,
297 false /* onlyShowCenteredIcon */);
Selim Cinek9bfc7a52018-06-11 16:09:00 -0700298 }
299
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700300 public void updateStatusBarIcons() {
Selim Cinekd03518c2018-03-15 12:13:51 -0700301 updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
Beverly40770652019-02-15 15:49:49 -0500302 false /* showAmbient */,
Gus Prevasdddef392018-11-02 15:41:43 -0400303 true /* hideDismissed */,
Lucas Dupin20403372019-02-14 19:59:18 -0800304 true /* hideRepliedMessages */,
Beverly40770652019-02-15 15:49:49 -0500305 false /* hideCurrentMedia */,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700306 true /* hide centered icon */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400307 false /* hidePulsing */,
308 false /* onlyShowCenteredIcon */);
Beverly40770652019-02-15 15:49:49 -0500309 }
310
311 private void updateCenterIcon() {
312 updateIconsForLayout(entry -> entry.centeredIcon, mCenteredIcon,
313 false /* showAmbient */,
Beverly40770652019-02-15 15:49:49 -0500314 false /* hideDismissed */,
315 false /* hideRepliedMessages */,
Selim Cinek195dfc52019-05-30 19:35:05 -0700316 false /* hideCurrentMedia */,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700317 false /* hide centered icon */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400318 false /* hidePulsing */,
319 true/* onlyShowCenteredIcon */);
Selim Cinekd03518c2018-03-15 12:13:51 -0700320 }
321
Selim Cinek999230c2019-06-19 15:36:44 -0700322 public void updateAodNotificationIcons() {
Selim Cinek195dfc52019-05-30 19:35:05 -0700323 updateIconsForLayout(entry -> entry.aodIcon, mAodIcons,
324 false /* showAmbient */,
Selim Cinek195dfc52019-05-30 19:35:05 -0700325 true /* hideDismissed */,
326 true /* hideRepliedMessages */,
327 true /* hideCurrentMedia */,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700328 true /* hide centered icon */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400329 mBypassController.getBypassEnabled() /* hidePulsing */,
330 false /* onlyShowCenteredIcon */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700331 }
332
Selim Cinek281c2022016-10-13 19:14:43 -0700333 /**
334 * Updates the notification icons for a host layout. This will ensure that the notification
335 * host layout will have the same icons like the ones in here.
Selim Cinek281c2022016-10-13 19:14:43 -0700336 * @param function A function to look up an icon view based on an entry
337 * @param hostLayout which layout should be updated
Selim Cinek17e1b692016-12-02 18:19:11 -0800338 * @param showAmbient should ambient notification icons be shown
Selim Cinekd03518c2018-03-15 12:13:51 -0700339 * @param hideDismissed should dismissed icons be hidden
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700340 * @param hideRepliedMessages should messages that have been replied to be hidden
Selim Cinek820ba2d2019-06-18 18:59:09 -0700341 * @param hidePulsing should pulsing notifications be hidden
Selim Cinek281c2022016-10-13 19:14:43 -0700342 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500343 private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
Selim Cinek31ebb402019-07-19 18:29:56 -0700344 NotificationIconContainer hostLayout, boolean showAmbient,
Beverly40770652019-02-15 15:49:49 -0500345 boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400346 boolean hideCenteredIcon, boolean hidePulsing, boolean onlyShowCenteredIcon) {
Selim Cinek281c2022016-10-13 19:14:43 -0700347 ArrayList<StatusBarIconView> toShow = new ArrayList<>(
348 mNotificationScrollLayout.getChildCount());
Anthony Chen83092c62016-01-11 17:00:36 -0800349
350 // Filter out ambient notifications and notification children.
Selim Cinek281c2022016-10-13 19:14:43 -0700351 for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
352 View view = mNotificationScrollLayout.getChildAt(i);
353 if (view instanceof ExpandableNotificationRow) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500354 NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
Selim Cinek31ebb402019-07-19 18:29:56 -0700355 if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400356 hideRepliedMessages, hideCurrentMedia, hideCenteredIcon, hidePulsing,
357 onlyShowCenteredIcon)) {
Beverly40770652019-02-15 15:49:49 -0500358 StatusBarIconView iconView = function.apply(ent);
359 if (iconView != null) {
360 toShow.add(iconView);
361 }
Selim Cinek281c2022016-10-13 19:14:43 -0700362 }
Anthony Chen83092c62016-01-11 17:00:36 -0800363 }
Anthony Chen83092c62016-01-11 17:00:36 -0800364 }
365
Selim Cinek72fc8db2017-06-06 18:07:47 -0700366 // In case we are changing the suppression of a group, the replacement shouldn't flicker
367 // and it should just be replaced instead. We therefore look for notifications that were
368 // just replaced by the child or vice-versa to suppress this.
Selim Cinek49014f82016-11-04 14:55:30 -0700369
Selim Cinek72fc8db2017-06-06 18:07:47 -0700370 ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons = new ArrayMap<>();
Anthony Chen83092c62016-01-11 17:00:36 -0800371 ArrayList<View> toRemove = new ArrayList<>();
Selim Cinek281c2022016-10-13 19:14:43 -0700372 for (int i = 0; i < hostLayout.getChildCount(); i++) {
373 View child = hostLayout.getChildAt(i);
Selim Cinek72fc8db2017-06-06 18:07:47 -0700374 if (!(child instanceof StatusBarIconView)) {
375 continue;
376 }
Anthony Chen83092c62016-01-11 17:00:36 -0800377 if (!toShow.contains(child)) {
Selim Cinek72fc8db2017-06-06 18:07:47 -0700378 boolean iconWasReplaced = false;
379 StatusBarIconView removedIcon = (StatusBarIconView) child;
380 String removedGroupKey = removedIcon.getNotification().getGroupKey();
381 for (int j = 0; j < toShow.size(); j++) {
382 StatusBarIconView candidate = toShow.get(j);
383 if (candidate.getSourceIcon().sameAs((removedIcon.getSourceIcon()))
384 && candidate.getNotification().getGroupKey().equals(removedGroupKey)) {
385 if (!iconWasReplaced) {
386 iconWasReplaced = true;
387 } else {
388 iconWasReplaced = false;
389 break;
390 }
391 }
392 }
393 if (iconWasReplaced) {
394 ArrayList<StatusBarIcon> statusBarIcons = replacingIcons.get(removedGroupKey);
395 if (statusBarIcons == null) {
396 statusBarIcons = new ArrayList<>();
397 replacingIcons.put(removedGroupKey, statusBarIcons);
398 }
399 statusBarIcons.add(removedIcon.getStatusBarIcon());
400 }
401 toRemove.add(removedIcon);
Anthony Chen83092c62016-01-11 17:00:36 -0800402 }
403 }
Selim Cinek72fc8db2017-06-06 18:07:47 -0700404 // removing all duplicates
405 ArrayList<String> duplicates = new ArrayList<>();
406 for (String key : replacingIcons.keySet()) {
407 ArrayList<StatusBarIcon> statusBarIcons = replacingIcons.get(key);
408 if (statusBarIcons.size() != 1) {
409 duplicates.add(key);
410 }
411 }
412 replacingIcons.removeAll(duplicates);
413 hostLayout.setReplacingIcons(replacingIcons);
Anthony Chen83092c62016-01-11 17:00:36 -0800414
415 final int toRemoveCount = toRemove.size();
416 for (int i = 0; i < toRemoveCount; i++) {
Selim Cinek281c2022016-10-13 19:14:43 -0700417 hostLayout.removeView(toRemove.get(i));
Anthony Chen83092c62016-01-11 17:00:36 -0800418 }
419
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800420 final FrameLayout.LayoutParams params = generateIconLayoutParams();
Anthony Chen83092c62016-01-11 17:00:36 -0800421 for (int i = 0; i < toShow.size(); i++) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700422 StatusBarIconView v = toShow.get(i);
Selim Cinek5b5beb012016-11-08 18:11:58 -0800423 // The view might still be transiently added if it was just removed and added again
424 hostLayout.removeTransientView(v);
Anthony Chen83092c62016-01-11 17:00:36 -0800425 if (v.getParent() == null) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700426 if (hideDismissed) {
427 v.setOnDismissListener(mUpdateStatusBarIcons);
428 }
Selim Cinek281c2022016-10-13 19:14:43 -0700429 hostLayout.addView(v, i, params);
Anthony Chen83092c62016-01-11 17:00:36 -0800430 }
431 }
432
Selim Cinek5b5beb012016-11-08 18:11:58 -0800433 hostLayout.setChangingViewPositions(true);
Anthony Chen83092c62016-01-11 17:00:36 -0800434 // Re-sort notification icons
Selim Cinek281c2022016-10-13 19:14:43 -0700435 final int childCount = hostLayout.getChildCount();
Anthony Chen83092c62016-01-11 17:00:36 -0800436 for (int i = 0; i < childCount; i++) {
Selim Cinek281c2022016-10-13 19:14:43 -0700437 View actual = hostLayout.getChildAt(i);
Anthony Chen83092c62016-01-11 17:00:36 -0800438 StatusBarIconView expected = toShow.get(i);
439 if (actual == expected) {
440 continue;
441 }
Selim Cinek281c2022016-10-13 19:14:43 -0700442 hostLayout.removeView(expected);
443 hostLayout.addView(expected, i);
Anthony Chen83092c62016-01-11 17:00:36 -0800444 }
Selim Cinek5b5beb012016-11-08 18:11:58 -0800445 hostLayout.setChangingViewPositions(false);
Selim Cinek72fc8db2017-06-06 18:07:47 -0700446 hostLayout.setReplacingIcons(null);
Anthony Chen83092c62016-01-11 17:00:36 -0800447 }
448
449 /**
450 * Applies {@link #mIconTint} to the notification icons.
Beverly40770652019-02-15 15:49:49 -0500451 * Applies {@link #mCenteredIconTint} to the center notification icon.
Anthony Chen83092c62016-01-11 17:00:36 -0800452 */
453 private void applyNotificationIconsTint() {
454 for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
Selim Cinek887da3c2017-10-06 13:37:32 -0700455 final StatusBarIconView iv = (StatusBarIconView) mNotificationIcons.getChildAt(i);
456 if (iv.getWidth() != 0) {
Beverly40770652019-02-15 15:49:49 -0500457 updateTintForIcon(iv, mIconTint);
Selim Cinek887da3c2017-10-06 13:37:32 -0700458 } else {
Beverly40770652019-02-15 15:49:49 -0500459 iv.executeOnLayout(() -> updateTintForIcon(iv, mIconTint));
460 }
461 }
462
463 for (int i = 0; i < mCenteredIcon.getChildCount(); i++) {
464 final StatusBarIconView iv = (StatusBarIconView) mCenteredIcon.getChildAt(i);
465 if (iv.getWidth() != 0) {
466 updateTintForIcon(iv, mCenteredIconTint);
467 } else {
468 iv.executeOnLayout(() -> updateTintForIcon(iv, mCenteredIconTint));
Anthony Chen83092c62016-01-11 17:00:36 -0800469 }
Anthony Chen83092c62016-01-11 17:00:36 -0800470 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700471
472 updateAodIconColors();
Anthony Chen83092c62016-01-11 17:00:36 -0800473 }
Lucas Dupin987f1932017-05-13 21:02:52 -0700474
Beverly40770652019-02-15 15:49:49 -0500475 private void updateTintForIcon(StatusBarIconView v, int tint) {
Selim Cinek887da3c2017-10-06 13:37:32 -0700476 boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
477 int color = StatusBarIconView.NO_COLOR;
Lucas Dupina291d192018-06-07 13:59:42 -0700478 boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mContrastColorUtil);
Selim Cinek887da3c2017-10-06 13:37:32 -0700479 if (colorize) {
Beverly40770652019-02-15 15:49:49 -0500480 color = DarkIconDispatcher.getTint(mTintArea, v, tint);
Selim Cinek887da3c2017-10-06 13:37:32 -0700481 }
482 v.setStaticDrawableColor(color);
Beverly40770652019-02-15 15:49:49 -0500483 v.setDecorColor(tint);
Selim Cinek887da3c2017-10-06 13:37:32 -0700484 }
485
Beverly40770652019-02-15 15:49:49 -0500486 /**
487 * Shows the icon view given in the center.
488 */
489 public void showIconCentered(NotificationEntry entry) {
490 StatusBarIconView icon = entry == null ? null : entry.centeredIcon;
491 if (!Objects.equals(mCenteredIconView, icon)) {
492 mCenteredIconView = icon;
493 updateNotificationIcons();
494 }
Lucas Dupin987f1932017-05-13 21:02:52 -0700495 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800496
Selim Cinek332c23f2018-03-16 17:37:50 -0700497 public void showIconIsolated(StatusBarIconView icon, boolean animated) {
498 mNotificationIcons.showIconIsolated(icon, animated);
499 }
500
501 public void setIsolatedIconLocation(Rect iconDrawingRect, boolean requireStateUpdate) {
502 mNotificationIcons.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800503 }
Lucas Dupin23a8d3b2018-10-08 20:57:35 -0700504
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800505 @Override
Selim Cinek195dfc52019-05-30 19:35:05 -0700506 public void onDozingChanged(boolean isDozing) {
507 boolean animate = mDozeParameters.getAlwaysOn()
508 && !mDozeParameters.getDisplayNeedsBlanking();
509 mAodIcons.setDozing(isDozing, animate, 0);
510 }
511
512 public void setAnimationsEnabled(boolean enabled) {
513 mAnimationsEnabled = enabled;
514 updateAnimations();
515 }
516
517 @Override
518 public void onStateChanged(int newState) {
Selim Cinek999230c2019-06-19 15:36:44 -0700519 updateAodIconsVisibility(false /* animate */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700520 updateAnimations();
521 }
522
523 private void updateAnimations() {
524 boolean inShade = mStatusBarStateController.getState() == StatusBarState.SHADE;
525 mAodIcons.setAnimationsEnabled(mAnimationsEnabled && !inShade);
526 mCenteredIcon.setAnimationsEnabled(mAnimationsEnabled && inShade);
527 mNotificationIcons.setAnimationsEnabled(mAnimationsEnabled && inShade);
528 }
529
530 public void onThemeChanged() {
531 reloadAodColor();
532 updateAodIconColors();
533 }
534
535 public void appearAodIcons() {
536 DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
537 if (dozeParameters.shouldControlScreenOff()) {
538 mAodIcons.setTranslationY(-mAodIconAppearTranslation);
539 mAodIcons.setAlpha(0);
Selim Cinek29f85852019-09-19 16:43:33 -0700540 animateInAodIconTranslation();
Selim Cinek195dfc52019-05-30 19:35:05 -0700541 mAodIcons.animate()
542 .alpha(1)
543 .setInterpolator(Interpolators.LINEAR)
544 .setDuration(AOD_ICONS_APPEAR_DURATION)
545 .start();
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800546 }
Lucas Dupin23a8d3b2018-10-08 20:57:35 -0700547 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700548
Selim Cinek29f85852019-09-19 16:43:33 -0700549 private void animateInAodIconTranslation() {
550 mAodIcons.animate()
551 .setInterpolator(Interpolators.DECELERATE_QUINT)
552 .translationY(0)
553 .setDuration(AOD_ICONS_APPEAR_DURATION)
554 .start();
555 }
556
Selim Cinek195dfc52019-05-30 19:35:05 -0700557 private void reloadAodColor() {
558 mAodIconTint = Utils.getColorAttrDefaultColor(mContext,
559 R.attr.wallpaperTextColor);
560 }
561 private void updateAodIconColors() {
562 for (int i = 0; i < mAodIcons.getChildCount(); i++) {
563 final StatusBarIconView iv = (StatusBarIconView) mAodIcons.getChildAt(i);
564 if (iv.getWidth() != 0) {
565 updateTintForIcon(iv, mAodIconTint);
566 } else {
567 iv.executeOnLayout(() -> updateTintForIcon(iv, mAodIconTint));
568 }
569 }
570 }
571
Selim Cinek820ba2d2019-06-18 18:59:09 -0700572 @Override
573 public void onFullyHiddenChanged(boolean fullyHidden) {
Selim Cinek999230c2019-06-19 15:36:44 -0700574 boolean animate = true;
575 if (!mBypassController.getBypassEnabled()) {
576 animate = mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking();
577 // We only want the appear animations to happen when the notifications get fully hidden,
578 // since otherwise the unhide animation overlaps
579 animate &= fullyHidden;
Selim Cinek820ba2d2019-06-18 18:59:09 -0700580 }
Selim Cinek999230c2019-06-19 15:36:44 -0700581 updateAodIconsVisibility(animate);
582 updateAodNotificationIcons();
Selim Cinek820ba2d2019-06-18 18:59:09 -0700583 }
584
585 @Override
586 public void onPulseExpansionChanged(boolean expandingChanged) {
587 if (expandingChanged) {
Selim Cinek999230c2019-06-19 15:36:44 -0700588 updateAodIconsVisibility(true /* animate */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700589 }
590 }
591
Selim Cinek999230c2019-06-19 15:36:44 -0700592 private void updateAodIconsVisibility(boolean animate) {
Selim Cinek820ba2d2019-06-18 18:59:09 -0700593 boolean visible = mBypassController.getBypassEnabled()
594 || mWakeUpCoordinator.getNotificationsFullyHidden();
595 if (mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
596 visible = false;
597 }
598 if (visible && mWakeUpCoordinator.isPulseExpanding()) {
599 visible = false;
600 }
Selim Cinek999230c2019-06-19 15:36:44 -0700601 if (mAodIconsVisible != visible) {
602 mAodIconsVisible = visible;
603 mAodIcons.animate().cancel();
604 if (animate) {
605 boolean wasFullyInvisible = mAodIcons.getVisibility() != View.VISIBLE;
606 if (mAodIconsVisible) {
607 if (wasFullyInvisible) {
608 // No fading here, let's just appear the icons instead!
609 mAodIcons.setVisibility(View.VISIBLE);
610 mAodIcons.setAlpha(1.0f);
611 appearAodIcons();
612 } else {
Selim Cinek29f85852019-09-19 16:43:33 -0700613 // Let's make sure the icon are translated to 0, since we cancelled it above
614 animateInAodIconTranslation();
Selim Cinek999230c2019-06-19 15:36:44 -0700615 // We were fading out, let's fade in instead
616 CrossFadeHelper.fadeIn(mAodIcons);
617 }
618 } else {
Selim Cinek29f85852019-09-19 16:43:33 -0700619 // Let's make sure the icon are translated to 0, since we cancelled it above
620 animateInAodIconTranslation();
Selim Cinek999230c2019-06-19 15:36:44 -0700621 CrossFadeHelper.fadeOut(mAodIcons);
622 }
623 } else {
624 mAodIcons.setAlpha(1.0f);
Selim Cinek29f85852019-09-19 16:43:33 -0700625 mAodIcons.setTranslationY(0);
Selim Cinek999230c2019-06-19 15:36:44 -0700626 mAodIcons.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
627 }
628 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700629 }
Anthony Chen83092c62016-01-11 17:00:36 -0800630}