blob: 707138ee8dc04f16731ee3a74a2f1a7b86e9ee31 [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 Cinek195dfc52019-05-30 19:35:05 -070018import com.android.systemui.Interpolators;
Anthony Chen83092c62016-01-11 17:00:36 -080019import com.android.systemui.R;
Beverly1be62f42018-12-19 17:17:48 -050020import com.android.systemui.plugins.DarkIconDispatcher;
21import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
Beverly8fdb5332019-02-04 14:29:49 -050022import com.android.systemui.plugins.statusbar.StatusBarStateController;
Selim Cinek999230c2019-06-19 15:36:44 -070023import com.android.systemui.statusbar.CrossFadeHelper;
Lucas Dupin20403372019-02-14 19:59:18 -080024import com.android.systemui.statusbar.NotificationMediaManager;
Selim Cinek281c2022016-10-13 19:14:43 -070025import com.android.systemui.statusbar.NotificationShelf;
Anthony Chen83092c62016-01-11 17:00:36 -080026import com.android.systemui.statusbar.StatusBarIconView;
Selim Cinek195dfc52019-05-30 19:35:05 -070027import com.android.systemui.statusbar.StatusBarState;
Anthony Chen83092c62016-01-11 17:00:36 -080028import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cinek820ba2d2019-06-18 18:59:09 -070029import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
Ned Burnsf81c4c42019-01-07 14:10:43 -050030import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Gus Prevas33619af2018-10-26 15:40:27 -040031import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Anthony Chen83092c62016-01-11 17:00:36 -080032
33import java.util.ArrayList;
Beverly40770652019-02-15 15:49:49 -050034import java.util.Objects;
Selim Cinek281c2022016-10-13 19:14:43 -070035import java.util.function.Function;
Anthony Chen83092c62016-01-11 17:00:36 -080036
37/**
38 * A controller for the space in the status bar to the left of the system icons. This area is
39 * normally reserved for notifications.
40 */
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080041public class NotificationIconAreaController implements DarkReceiver,
Selim Cinek820ba2d2019-06-18 18:59:09 -070042 StatusBarStateController.StateListener,
43 NotificationWakeUpCoordinator.WakeUpListener {
Gus Prevas33619af2018-10-26 15:40:27 -040044
Selim Cinekda330ff2019-06-11 15:41:28 -070045 public static final String HIGH_PRIORITY = "high_priority";
Selim Cinek195dfc52019-05-30 19:35:05 -070046 private static final long AOD_ICONS_APPEAR_DURATION = 200;
Gus Prevas33619af2018-10-26 15:40:27 -040047
Lucas Dupina291d192018-06-07 13:59:42 -070048 private final ContrastColorUtil mContrastColorUtil;
Selim Cinekd03518c2018-03-15 12:13:51 -070049 private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080050 private final StatusBarStateController mStatusBarStateController;
Lucas Dupin20403372019-02-14 19:59:18 -080051 private final NotificationMediaManager mMediaManager;
Selim Cinek820ba2d2019-06-18 18:59:09 -070052 private final NotificationWakeUpCoordinator mWakeUpCoordinator;
53 private final KeyguardBypassController mBypassController;
Selim Cinek195dfc52019-05-30 19:35:05 -070054 private final DozeParameters mDozeParameters;
Anthony Chen83092c62016-01-11 17:00:36 -080055
56 private int mIconSize;
57 private int mIconHPadding;
58 private int mIconTint = Color.WHITE;
Beverly40770652019-02-15 15:49:49 -050059 private int mCenteredIconTint = Color.WHITE;
Anthony Chen83092c62016-01-11 17:00:36 -080060
Jason Monk2a6ea9c2017-01-26 11:14:51 -050061 private StatusBar mStatusBar;
Anthony Chen83092c62016-01-11 17:00:36 -080062 protected View mNotificationIconArea;
Selim Cinek281c2022016-10-13 19:14:43 -070063 private NotificationIconContainer mNotificationIcons;
Selim Cinek5b5beb012016-11-08 18:11:58 -080064 private NotificationIconContainer mShelfIcons;
Beverly40770652019-02-15 15:49:49 -050065 protected View mCenteredIconArea;
66 private NotificationIconContainer mCenteredIcon;
Selim Cinek195dfc52019-05-30 19:35:05 -070067 private NotificationIconContainer mAodIcons;
Beverly40770652019-02-15 15:49:49 -050068 private StatusBarIconView mCenteredIconView;
Jorim Jaggi86905582016-02-09 21:36:09 -080069 private final Rect mTintArea = new Rect();
Jason Monke59dc402018-08-16 12:05:01 -040070 private ViewGroup mNotificationScrollLayout;
Selim Cinek281c2022016-10-13 19:14:43 -070071 private Context mContext;
Selim Cinek195dfc52019-05-30 19:35:05 -070072 private int mAodIconAppearTranslation;
Anthony Chen83092c62016-01-11 17:00:36 -080073
Selim Cinek195dfc52019-05-30 19:35:05 -070074 private boolean mAnimationsEnabled;
75 private int mAodIconTint;
76 private boolean mFullyHidden;
Selim Cinek999230c2019-06-19 15:36:44 -070077 private boolean mAodIconsVisible;
Selim Cinek65c96f22019-07-25 20:09:04 -070078 private boolean mIsPulsing;
Lucas Dupin23a8d3b2018-10-08 20:57:35 -070079
Dave Mankoff2aff6c32019-10-14 17:40:37 -040080 public NotificationIconAreaController(
81 Context context,
82 StatusBar statusBar,
Julia Reynolds12ad7ca2019-01-28 09:29:16 -050083 StatusBarStateController statusBarStateController,
Selim Cinek820ba2d2019-06-18 18:59:09 -070084 NotificationWakeUpCoordinator wakeUpCoordinator,
85 KeyguardBypassController keyguardBypassController,
Dave Mankoff2aff6c32019-10-14 17:40:37 -040086 NotificationMediaManager notificationMediaManager,
87 DozeParameters dozeParameters) {
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;
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080091 mStatusBarStateController = statusBarStateController;
92 mStatusBarStateController.addCallback(this);
Lucas Dupin20403372019-02-14 19:59:18 -080093 mMediaManager = notificationMediaManager;
Dave Mankoff2aff6c32019-10-14 17:40:37 -040094 mDozeParameters = dozeParameters;
Selim Cinek820ba2d2019-06-18 18:59:09 -070095 mWakeUpCoordinator = wakeUpCoordinator;
96 wakeUpCoordinator.addListener(this);
97 mBypassController = keyguardBypassController;
Gus Prevas33619af2018-10-26 15:40:27 -040098
Anthony Chen83092c62016-01-11 17:00:36 -080099 initializeNotificationAreaViews(context);
Selim Cinek195dfc52019-05-30 19:35:05 -0700100 reloadAodColor();
Anthony Chen83092c62016-01-11 17:00:36 -0800101 }
102
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700103 protected View inflateIconArea(LayoutInflater inflater) {
104 return inflater.inflate(R.layout.notification_icon_area, null);
105 }
106
Anthony Chen83092c62016-01-11 17:00:36 -0800107 /**
108 * Initializes the views that will represent the notification area.
109 */
110 protected void initializeNotificationAreaViews(Context context) {
Selim Cinek3e7592d2016-04-11 09:35:54 +0800111 reloadDimens(context);
Anthony Chen83092c62016-01-11 17:00:36 -0800112
113 LayoutInflater layoutInflater = LayoutInflater.from(context);
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700114 mNotificationIconArea = inflateIconArea(layoutInflater);
Jason Monke59dc402018-08-16 12:05:01 -0400115 mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);
Anthony Chen83092c62016-01-11 17:00:36 -0800116
Jason Monkaa573e92017-01-27 17:00:29 -0500117 mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
Beverly40770652019-02-15 15:49:49 -0500118
119 mCenteredIconArea = layoutInflater.inflate(R.layout.center_icon_area, null);
120 mCenteredIcon = mCenteredIconArea.findViewById(R.id.centeredIcon);
Selim Cinek195dfc52019-05-30 19:35:05 -0700121
122 initAodIcons();
123 }
124
125 public void initAodIcons() {
126 boolean changed = mAodIcons != null;
127 if (changed) {
128 mAodIcons.setAnimationsEnabled(false);
129 mAodIcons.removeAllViews();
130 }
wilsonshihe8321942019-10-18 18:39:46 +0800131 mAodIcons = mStatusBar.getNotificationShadeWindowView().findViewById(
Selim Cinek195dfc52019-05-30 19:35:05 -0700132 R.id.clock_notification_icon_container);
133 mAodIcons.setOnLockScreen(true);
Selim Cinek999230c2019-06-19 15:36:44 -0700134 updateAodIconsVisibility(false /* animate */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700135 updateAnimations();
136 if (changed) {
Selim Cinek999230c2019-06-19 15:36:44 -0700137 updateAodNotificationIcons();
Selim Cinek195dfc52019-05-30 19:35:05 -0700138 }
Jason Monkaa573e92017-01-27 17:00:29 -0500139 }
140
141 public void setupShelf(NotificationShelf shelf) {
Selim Cinek5b5beb012016-11-08 18:11:58 -0800142 mShelfIcons = shelf.getShelfIcons();
Selim Cinek49014f82016-11-04 14:55:30 -0700143 shelf.setCollapsedIcons(mNotificationIcons);
Anthony Chen83092c62016-01-11 17:00:36 -0800144 }
145
Selim Cinek3e7592d2016-04-11 09:35:54 +0800146 public void onDensityOrFontScaleChanged(Context context) {
147 reloadDimens(context);
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800148 final FrameLayout.LayoutParams params = generateIconLayoutParams();
Selim Cinek3e7592d2016-04-11 09:35:54 +0800149 for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
150 View child = mNotificationIcons.getChildAt(i);
151 child.setLayoutParams(params);
Selim Cinek9ef119c2017-03-01 15:13:36 -0800152 }
153 for (int i = 0; i < mShelfIcons.getChildCount(); i++) {
154 View child = mShelfIcons.getChildAt(i);
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800155 child.setLayoutParams(params);
Selim Cinek3e7592d2016-04-11 09:35:54 +0800156 }
Beverly40770652019-02-15 15:49:49 -0500157 for (int i = 0; i < mCenteredIcon.getChildCount(); i++) {
158 View child = mCenteredIcon.getChildAt(i);
159 child.setLayoutParams(params);
160 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700161 for (int i = 0; i < mAodIcons.getChildCount(); i++) {
162 View child = mAodIcons.getChildAt(i);
163 child.setLayoutParams(params);
164 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800165 }
166
167 @NonNull
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800168 private FrameLayout.LayoutParams generateIconLayoutParams() {
169 return new FrameLayout.LayoutParams(
Selim Cinek3e7592d2016-04-11 09:35:54 +0800170 mIconSize + 2 * mIconHPadding, getHeight());
171 }
172
173 private void reloadDimens(Context context) {
174 Resources res = context.getResources();
175 mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
176 mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
Selim Cinek195dfc52019-05-30 19:35:05 -0700177 mAodIconAppearTranslation = res.getDimensionPixelSize(
178 R.dimen.shelf_appear_translation);
Selim Cinek3e7592d2016-04-11 09:35:54 +0800179 }
180
Anthony Chen83092c62016-01-11 17:00:36 -0800181 /**
182 * Returns the view that represents the notification area.
183 */
184 public View getNotificationInnerAreaView() {
185 return mNotificationIconArea;
186 }
187
188 /**
Beverly40770652019-02-15 15:49:49 -0500189 * Returns the view that represents the centered notification area.
190 */
191 public View getCenteredNotificationAreaView() {
192 return mCenteredIconArea;
193 }
194
195 /**
Jason Monkaa573e92017-01-27 17:00:29 -0500196 * See {@link com.android.systemui.statusbar.policy.DarkIconDispatcher#setIconsDarkArea}.
197 * Sets the color that should be used to tint any icons in the notification area.
Jorim Jaggi86905582016-02-09 21:36:09 -0800198 *
199 * @param tintArea the area in which to tint the icons, specified in screen coordinates
Jason Monkaa573e92017-01-27 17:00:29 -0500200 * @param darkIntensity
Jorim Jaggi86905582016-02-09 21:36:09 -0800201 */
Jason Monkaa573e92017-01-27 17:00:29 -0500202 public void onDarkChanged(Rect tintArea, float darkIntensity, int iconTint) {
Jorim Jaggi86905582016-02-09 21:36:09 -0800203 if (tintArea == null) {
204 mTintArea.setEmpty();
205 } else {
206 mTintArea.set(tintArea);
207 }
Beverly40770652019-02-15 15:49:49 -0500208
Evan Lairddbeefe32018-04-03 16:52:41 -0400209 if (mNotificationIconArea != null) {
210 if (DarkIconDispatcher.isInArea(tintArea, mNotificationIconArea)) {
211 mIconTint = iconTint;
212 }
213 } else {
214 mIconTint = iconTint;
215 }
216
Beverly40770652019-02-15 15:49:49 -0500217 if (mCenteredIconArea != null) {
218 if (DarkIconDispatcher.isInArea(tintArea, mCenteredIconArea)) {
219 mCenteredIconTint = iconTint;
220 }
221 } else {
222 mCenteredIconTint = iconTint;
223 }
224
Anthony Chen83092c62016-01-11 17:00:36 -0800225 applyNotificationIconsTint();
226 }
227
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700228 protected int getHeight() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500229 return mStatusBar.getStatusBarHeight();
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700230 }
231
Ned Burnsf81c4c42019-01-07 14:10:43 -0500232 protected boolean shouldShowNotificationIcon(NotificationEntry entry,
Selim Cinek31ebb402019-07-19 18:29:56 -0700233 boolean showAmbient, boolean hideDismissed,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700234 boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400235 boolean hidePulsing, boolean onlyShowCenteredIcon) {
Beverly40770652019-02-15 15:49:49 -0500236
Beverlyfd3b1dca2019-06-25 16:21:00 -0400237 final boolean isCenteredNotificationIcon = mCenteredIconView != null
238 && entry.centeredIcon != null
Beverly40770652019-02-15 15:49:49 -0500239 && Objects.equals(entry.centeredIcon, mCenteredIconView);
Beverlyfd3b1dca2019-06-25 16:21:00 -0400240 if (onlyShowCenteredIcon) {
241 return isCenteredNotificationIcon;
242 }
Selim Cineke3c6e462019-06-24 19:37:06 -0700243 if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
Beverly40770652019-02-15 15:49:49 -0500244 return false;
245 }
Evan Laird181de622019-10-24 09:53:02 -0400246 if (entry.getRanking().isAmbient() && !showAmbient) {
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700247 return false;
248 }
Ned Burns00b4b2d2019-10-17 22:09:27 -0400249 if (hideCurrentMedia && entry.getKey().equals(mMediaManager.getMediaNotificationKey())) {
Lucas Dupin20403372019-02-14 19:59:18 -0800250 return false;
251 }
Evan Laird94492852018-10-25 13:43:01 -0400252 if (!entry.isTopLevelChild()) {
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700253 return false;
254 }
Evan Laird94492852018-10-25 13:43:01 -0400255 if (entry.getRow().getVisibility() == View.GONE) {
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700256 return false;
257 }
Evan Laird94492852018-10-25 13:43:01 -0400258 if (entry.isRowDismissed() && hideDismissed) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700259 return false;
260 }
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700261 if (hideRepliedMessages && entry.isLastMessageFromReply()) {
262 return false;
263 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -0500264 // showAmbient == show in shade but not shelf
Selim Cinek195dfc52019-05-30 19:35:05 -0700265 if (!showAmbient && entry.shouldSuppressStatusBar()) {
Julia Reynoldsc861a3d2018-02-15 10:34:49 -0500266 return false;
267 }
Selim Cinek65c96f22019-07-25 20:09:04 -0700268 if (hidePulsing && entry.showingPulsing()
269 && (!mWakeUpCoordinator.getNotificationsFullyHidden()
270 || !entry.isPulseSuppressed())) {
Selim Cinek820ba2d2019-06-18 18:59:09 -0700271 return false;
272 }
Xiaohui Cheneb04a992016-03-22 14:58:03 -0700273 return true;
274 }
275
Anthony Chen83092c62016-01-11 17:00:36 -0800276 /**
277 * Updates the notifications with the given list of notifications to display.
278 */
Selim Cinekd03518c2018-03-15 12:13:51 -0700279 public void updateNotificationIcons() {
Selim Cinekd03518c2018-03-15 12:13:51 -0700280 updateStatusBarIcons();
Selim Cinek9bfc7a52018-06-11 16:09:00 -0700281 updateShelfIcons();
Beverly40770652019-02-15 15:49:49 -0500282 updateCenterIcon();
Selim Cinek999230c2019-06-19 15:36:44 -0700283 updateAodNotificationIcons();
Selim Cinek281c2022016-10-13 19:14:43 -0700284
285 applyNotificationIconsTint();
Selim Cinek281c2022016-10-13 19:14:43 -0700286 }
287
Selim Cinek9bfc7a52018-06-11 16:09:00 -0700288 private void updateShelfIcons() {
289 updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
Beverly40770652019-02-15 15:49:49 -0500290 true /* showAmbient */,
Beverly40770652019-02-15 15:49:49 -0500291 false /* hideDismissed */,
Selim Cinek195dfc52019-05-30 19:35:05 -0700292 false /* hideRepliedMessages */,
293 false /* hideCurrentMedia */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400294 false /* hide centered icon */,
295 false /* hidePulsing */,
296 false /* onlyShowCenteredIcon */);
Selim Cinek9bfc7a52018-06-11 16:09:00 -0700297 }
298
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700299 public void updateStatusBarIcons() {
Selim Cinekd03518c2018-03-15 12:13:51 -0700300 updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
Beverly40770652019-02-15 15:49:49 -0500301 false /* showAmbient */,
Gus Prevasdddef392018-11-02 15:41:43 -0400302 true /* hideDismissed */,
Lucas Dupin20403372019-02-14 19:59:18 -0800303 true /* hideRepliedMessages */,
Beverly40770652019-02-15 15:49:49 -0500304 false /* hideCurrentMedia */,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700305 true /* hide centered icon */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400306 false /* hidePulsing */,
307 false /* onlyShowCenteredIcon */);
Beverly40770652019-02-15 15:49:49 -0500308 }
309
310 private void updateCenterIcon() {
311 updateIconsForLayout(entry -> entry.centeredIcon, mCenteredIcon,
312 false /* showAmbient */,
Beverly40770652019-02-15 15:49:49 -0500313 false /* hideDismissed */,
314 false /* hideRepliedMessages */,
Selim Cinek195dfc52019-05-30 19:35:05 -0700315 false /* hideCurrentMedia */,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700316 false /* hide centered icon */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400317 false /* hidePulsing */,
318 true/* onlyShowCenteredIcon */);
Selim Cinekd03518c2018-03-15 12:13:51 -0700319 }
320
Selim Cinek999230c2019-06-19 15:36:44 -0700321 public void updateAodNotificationIcons() {
Selim Cinek195dfc52019-05-30 19:35:05 -0700322 updateIconsForLayout(entry -> entry.aodIcon, mAodIcons,
323 false /* showAmbient */,
Selim Cinek195dfc52019-05-30 19:35:05 -0700324 true /* hideDismissed */,
325 true /* hideRepliedMessages */,
326 true /* hideCurrentMedia */,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700327 true /* hide centered icon */,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400328 mBypassController.getBypassEnabled() /* hidePulsing */,
329 false /* onlyShowCenteredIcon */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700330 }
331
Selim Cinek281c2022016-10-13 19:14:43 -0700332 /**
333 * Updates the notification icons for a host layout. This will ensure that the notification
334 * host layout will have the same icons like the ones in here.
Selim Cinek281c2022016-10-13 19:14:43 -0700335 * @param function A function to look up an icon view based on an entry
336 * @param hostLayout which layout should be updated
Selim Cinek17e1b692016-12-02 18:19:11 -0800337 * @param showAmbient should ambient notification icons be shown
Selim Cinekd03518c2018-03-15 12:13:51 -0700338 * @param hideDismissed should dismissed icons be hidden
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700339 * @param hideRepliedMessages should messages that have been replied to be hidden
Selim Cinek820ba2d2019-06-18 18:59:09 -0700340 * @param hidePulsing should pulsing notifications be hidden
Selim Cinek281c2022016-10-13 19:14:43 -0700341 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500342 private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
Selim Cinek31ebb402019-07-19 18:29:56 -0700343 NotificationIconContainer hostLayout, boolean showAmbient,
Beverly40770652019-02-15 15:49:49 -0500344 boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400345 boolean hideCenteredIcon, boolean hidePulsing, boolean onlyShowCenteredIcon) {
Selim Cinek281c2022016-10-13 19:14:43 -0700346 ArrayList<StatusBarIconView> toShow = new ArrayList<>(
347 mNotificationScrollLayout.getChildCount());
Anthony Chen83092c62016-01-11 17:00:36 -0800348
349 // Filter out ambient notifications and notification children.
Selim Cinek281c2022016-10-13 19:14:43 -0700350 for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
351 View view = mNotificationScrollLayout.getChildAt(i);
352 if (view instanceof ExpandableNotificationRow) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500353 NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
Selim Cinek31ebb402019-07-19 18:29:56 -0700354 if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
Beverlyfd3b1dca2019-06-25 16:21:00 -0400355 hideRepliedMessages, hideCurrentMedia, hideCenteredIcon, hidePulsing,
356 onlyShowCenteredIcon)) {
Beverly40770652019-02-15 15:49:49 -0500357 StatusBarIconView iconView = function.apply(ent);
358 if (iconView != null) {
359 toShow.add(iconView);
360 }
Selim Cinek281c2022016-10-13 19:14:43 -0700361 }
Anthony Chen83092c62016-01-11 17:00:36 -0800362 }
Anthony Chen83092c62016-01-11 17:00:36 -0800363 }
364
Selim Cinek72fc8db2017-06-06 18:07:47 -0700365 // In case we are changing the suppression of a group, the replacement shouldn't flicker
366 // and it should just be replaced instead. We therefore look for notifications that were
367 // just replaced by the child or vice-versa to suppress this.
Selim Cinek49014f82016-11-04 14:55:30 -0700368
Selim Cinek72fc8db2017-06-06 18:07:47 -0700369 ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons = new ArrayMap<>();
Anthony Chen83092c62016-01-11 17:00:36 -0800370 ArrayList<View> toRemove = new ArrayList<>();
Selim Cinek281c2022016-10-13 19:14:43 -0700371 for (int i = 0; i < hostLayout.getChildCount(); i++) {
372 View child = hostLayout.getChildAt(i);
Selim Cinek72fc8db2017-06-06 18:07:47 -0700373 if (!(child instanceof StatusBarIconView)) {
374 continue;
375 }
Anthony Chen83092c62016-01-11 17:00:36 -0800376 if (!toShow.contains(child)) {
Selim Cinek72fc8db2017-06-06 18:07:47 -0700377 boolean iconWasReplaced = false;
378 StatusBarIconView removedIcon = (StatusBarIconView) child;
379 String removedGroupKey = removedIcon.getNotification().getGroupKey();
380 for (int j = 0; j < toShow.size(); j++) {
381 StatusBarIconView candidate = toShow.get(j);
382 if (candidate.getSourceIcon().sameAs((removedIcon.getSourceIcon()))
383 && candidate.getNotification().getGroupKey().equals(removedGroupKey)) {
384 if (!iconWasReplaced) {
385 iconWasReplaced = true;
386 } else {
387 iconWasReplaced = false;
388 break;
389 }
390 }
391 }
392 if (iconWasReplaced) {
393 ArrayList<StatusBarIcon> statusBarIcons = replacingIcons.get(removedGroupKey);
394 if (statusBarIcons == null) {
395 statusBarIcons = new ArrayList<>();
396 replacingIcons.put(removedGroupKey, statusBarIcons);
397 }
398 statusBarIcons.add(removedIcon.getStatusBarIcon());
399 }
400 toRemove.add(removedIcon);
Anthony Chen83092c62016-01-11 17:00:36 -0800401 }
402 }
Selim Cinek72fc8db2017-06-06 18:07:47 -0700403 // removing all duplicates
404 ArrayList<String> duplicates = new ArrayList<>();
405 for (String key : replacingIcons.keySet()) {
406 ArrayList<StatusBarIcon> statusBarIcons = replacingIcons.get(key);
407 if (statusBarIcons.size() != 1) {
408 duplicates.add(key);
409 }
410 }
411 replacingIcons.removeAll(duplicates);
412 hostLayout.setReplacingIcons(replacingIcons);
Anthony Chen83092c62016-01-11 17:00:36 -0800413
414 final int toRemoveCount = toRemove.size();
415 for (int i = 0; i < toRemoveCount; i++) {
Selim Cinek281c2022016-10-13 19:14:43 -0700416 hostLayout.removeView(toRemove.get(i));
Anthony Chen83092c62016-01-11 17:00:36 -0800417 }
418
Selim Cinek0e8d77e2016-11-29 10:35:42 -0800419 final FrameLayout.LayoutParams params = generateIconLayoutParams();
Anthony Chen83092c62016-01-11 17:00:36 -0800420 for (int i = 0; i < toShow.size(); i++) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700421 StatusBarIconView v = toShow.get(i);
Selim Cinek5b5beb012016-11-08 18:11:58 -0800422 // The view might still be transiently added if it was just removed and added again
423 hostLayout.removeTransientView(v);
Anthony Chen83092c62016-01-11 17:00:36 -0800424 if (v.getParent() == null) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700425 if (hideDismissed) {
426 v.setOnDismissListener(mUpdateStatusBarIcons);
427 }
Selim Cinek281c2022016-10-13 19:14:43 -0700428 hostLayout.addView(v, i, params);
Anthony Chen83092c62016-01-11 17:00:36 -0800429 }
430 }
431
Selim Cinek5b5beb012016-11-08 18:11:58 -0800432 hostLayout.setChangingViewPositions(true);
Anthony Chen83092c62016-01-11 17:00:36 -0800433 // Re-sort notification icons
Selim Cinek281c2022016-10-13 19:14:43 -0700434 final int childCount = hostLayout.getChildCount();
Anthony Chen83092c62016-01-11 17:00:36 -0800435 for (int i = 0; i < childCount; i++) {
Selim Cinek281c2022016-10-13 19:14:43 -0700436 View actual = hostLayout.getChildAt(i);
Anthony Chen83092c62016-01-11 17:00:36 -0800437 StatusBarIconView expected = toShow.get(i);
438 if (actual == expected) {
439 continue;
440 }
Selim Cinek281c2022016-10-13 19:14:43 -0700441 hostLayout.removeView(expected);
442 hostLayout.addView(expected, i);
Anthony Chen83092c62016-01-11 17:00:36 -0800443 }
Selim Cinek5b5beb012016-11-08 18:11:58 -0800444 hostLayout.setChangingViewPositions(false);
Selim Cinek72fc8db2017-06-06 18:07:47 -0700445 hostLayout.setReplacingIcons(null);
Anthony Chen83092c62016-01-11 17:00:36 -0800446 }
447
448 /**
449 * Applies {@link #mIconTint} to the notification icons.
Beverly40770652019-02-15 15:49:49 -0500450 * Applies {@link #mCenteredIconTint} to the center notification icon.
Anthony Chen83092c62016-01-11 17:00:36 -0800451 */
452 private void applyNotificationIconsTint() {
453 for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
Selim Cinek887da3c2017-10-06 13:37:32 -0700454 final StatusBarIconView iv = (StatusBarIconView) mNotificationIcons.getChildAt(i);
455 if (iv.getWidth() != 0) {
Beverly40770652019-02-15 15:49:49 -0500456 updateTintForIcon(iv, mIconTint);
Selim Cinek887da3c2017-10-06 13:37:32 -0700457 } else {
Beverly40770652019-02-15 15:49:49 -0500458 iv.executeOnLayout(() -> updateTintForIcon(iv, mIconTint));
459 }
460 }
461
462 for (int i = 0; i < mCenteredIcon.getChildCount(); i++) {
463 final StatusBarIconView iv = (StatusBarIconView) mCenteredIcon.getChildAt(i);
464 if (iv.getWidth() != 0) {
465 updateTintForIcon(iv, mCenteredIconTint);
466 } else {
467 iv.executeOnLayout(() -> updateTintForIcon(iv, mCenteredIconTint));
Anthony Chen83092c62016-01-11 17:00:36 -0800468 }
Anthony Chen83092c62016-01-11 17:00:36 -0800469 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700470
471 updateAodIconColors();
Anthony Chen83092c62016-01-11 17:00:36 -0800472 }
Lucas Dupin987f1932017-05-13 21:02:52 -0700473
Beverly40770652019-02-15 15:49:49 -0500474 private void updateTintForIcon(StatusBarIconView v, int tint) {
Selim Cinek887da3c2017-10-06 13:37:32 -0700475 boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
476 int color = StatusBarIconView.NO_COLOR;
Lucas Dupina291d192018-06-07 13:59:42 -0700477 boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mContrastColorUtil);
Selim Cinek887da3c2017-10-06 13:37:32 -0700478 if (colorize) {
Beverly40770652019-02-15 15:49:49 -0500479 color = DarkIconDispatcher.getTint(mTintArea, v, tint);
Selim Cinek887da3c2017-10-06 13:37:32 -0700480 }
481 v.setStaticDrawableColor(color);
Beverly40770652019-02-15 15:49:49 -0500482 v.setDecorColor(tint);
Selim Cinek887da3c2017-10-06 13:37:32 -0700483 }
484
Beverly40770652019-02-15 15:49:49 -0500485 /**
486 * Shows the icon view given in the center.
487 */
488 public void showIconCentered(NotificationEntry entry) {
489 StatusBarIconView icon = entry == null ? null : entry.centeredIcon;
490 if (!Objects.equals(mCenteredIconView, icon)) {
491 mCenteredIconView = icon;
492 updateNotificationIcons();
493 }
Lucas Dupin987f1932017-05-13 21:02:52 -0700494 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800495
Selim Cinek332c23f2018-03-16 17:37:50 -0700496 public void showIconIsolated(StatusBarIconView icon, boolean animated) {
497 mNotificationIcons.showIconIsolated(icon, animated);
498 }
499
500 public void setIsolatedIconLocation(Rect iconDrawingRect, boolean requireStateUpdate) {
501 mNotificationIcons.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800502 }
Lucas Dupin23a8d3b2018-10-08 20:57:35 -0700503
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800504 @Override
Selim Cinek195dfc52019-05-30 19:35:05 -0700505 public void onDozingChanged(boolean isDozing) {
506 boolean animate = mDozeParameters.getAlwaysOn()
507 && !mDozeParameters.getDisplayNeedsBlanking();
508 mAodIcons.setDozing(isDozing, animate, 0);
509 }
510
511 public void setAnimationsEnabled(boolean enabled) {
512 mAnimationsEnabled = enabled;
513 updateAnimations();
514 }
515
516 @Override
517 public void onStateChanged(int newState) {
Selim Cinek999230c2019-06-19 15:36:44 -0700518 updateAodIconsVisibility(false /* animate */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700519 updateAnimations();
520 }
521
522 private void updateAnimations() {
523 boolean inShade = mStatusBarStateController.getState() == StatusBarState.SHADE;
524 mAodIcons.setAnimationsEnabled(mAnimationsEnabled && !inShade);
525 mCenteredIcon.setAnimationsEnabled(mAnimationsEnabled && inShade);
526 mNotificationIcons.setAnimationsEnabled(mAnimationsEnabled && inShade);
527 }
528
529 public void onThemeChanged() {
530 reloadAodColor();
531 updateAodIconColors();
532 }
533
534 public void appearAodIcons() {
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400535 if (mDozeParameters.shouldControlScreenOff()) {
Selim Cinek195dfc52019-05-30 19:35:05 -0700536 mAodIcons.setTranslationY(-mAodIconAppearTranslation);
537 mAodIcons.setAlpha(0);
Selim Cinek29f85852019-09-19 16:43:33 -0700538 animateInAodIconTranslation();
Selim Cinek195dfc52019-05-30 19:35:05 -0700539 mAodIcons.animate()
540 .alpha(1)
541 .setInterpolator(Interpolators.LINEAR)
542 .setDuration(AOD_ICONS_APPEAR_DURATION)
543 .start();
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800544 }
Lucas Dupin23a8d3b2018-10-08 20:57:35 -0700545 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700546
Selim Cinek29f85852019-09-19 16:43:33 -0700547 private void animateInAodIconTranslation() {
548 mAodIcons.animate()
549 .setInterpolator(Interpolators.DECELERATE_QUINT)
550 .translationY(0)
551 .setDuration(AOD_ICONS_APPEAR_DURATION)
552 .start();
553 }
554
Selim Cinek195dfc52019-05-30 19:35:05 -0700555 private void reloadAodColor() {
556 mAodIconTint = Utils.getColorAttrDefaultColor(mContext,
557 R.attr.wallpaperTextColor);
558 }
559 private void updateAodIconColors() {
560 for (int i = 0; i < mAodIcons.getChildCount(); i++) {
561 final StatusBarIconView iv = (StatusBarIconView) mAodIcons.getChildAt(i);
562 if (iv.getWidth() != 0) {
563 updateTintForIcon(iv, mAodIconTint);
564 } else {
565 iv.executeOnLayout(() -> updateTintForIcon(iv, mAodIconTint));
566 }
567 }
568 }
569
Selim Cinek820ba2d2019-06-18 18:59:09 -0700570 @Override
571 public void onFullyHiddenChanged(boolean fullyHidden) {
Selim Cinek999230c2019-06-19 15:36:44 -0700572 boolean animate = true;
573 if (!mBypassController.getBypassEnabled()) {
574 animate = mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking();
575 // We only want the appear animations to happen when the notifications get fully hidden,
576 // since otherwise the unhide animation overlaps
577 animate &= fullyHidden;
Selim Cinek820ba2d2019-06-18 18:59:09 -0700578 }
Selim Cinek999230c2019-06-19 15:36:44 -0700579 updateAodIconsVisibility(animate);
580 updateAodNotificationIcons();
Selim Cinek820ba2d2019-06-18 18:59:09 -0700581 }
582
583 @Override
584 public void onPulseExpansionChanged(boolean expandingChanged) {
585 if (expandingChanged) {
Selim Cinek999230c2019-06-19 15:36:44 -0700586 updateAodIconsVisibility(true /* animate */);
Selim Cinek195dfc52019-05-30 19:35:05 -0700587 }
588 }
589
Selim Cinek999230c2019-06-19 15:36:44 -0700590 private void updateAodIconsVisibility(boolean animate) {
Selim Cinek820ba2d2019-06-18 18:59:09 -0700591 boolean visible = mBypassController.getBypassEnabled()
592 || mWakeUpCoordinator.getNotificationsFullyHidden();
593 if (mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
594 visible = false;
595 }
596 if (visible && mWakeUpCoordinator.isPulseExpanding()) {
597 visible = false;
598 }
Selim Cinek999230c2019-06-19 15:36:44 -0700599 if (mAodIconsVisible != visible) {
600 mAodIconsVisible = visible;
601 mAodIcons.animate().cancel();
602 if (animate) {
603 boolean wasFullyInvisible = mAodIcons.getVisibility() != View.VISIBLE;
604 if (mAodIconsVisible) {
605 if (wasFullyInvisible) {
606 // No fading here, let's just appear the icons instead!
607 mAodIcons.setVisibility(View.VISIBLE);
608 mAodIcons.setAlpha(1.0f);
609 appearAodIcons();
610 } else {
Selim Cinek29f85852019-09-19 16:43:33 -0700611 // Let's make sure the icon are translated to 0, since we cancelled it above
612 animateInAodIconTranslation();
Selim Cinek999230c2019-06-19 15:36:44 -0700613 // We were fading out, let's fade in instead
614 CrossFadeHelper.fadeIn(mAodIcons);
615 }
616 } else {
Selim Cinek29f85852019-09-19 16:43:33 -0700617 // Let's make sure the icon are translated to 0, since we cancelled it above
618 animateInAodIconTranslation();
Selim Cinek999230c2019-06-19 15:36:44 -0700619 CrossFadeHelper.fadeOut(mAodIcons);
620 }
621 } else {
622 mAodIcons.setAlpha(1.0f);
Selim Cinek29f85852019-09-19 16:43:33 -0700623 mAodIcons.setTranslationY(0);
Selim Cinek999230c2019-06-19 15:36:44 -0700624 mAodIcons.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
625 }
626 }
Selim Cinek195dfc52019-05-30 19:35:05 -0700627 }
Anthony Chen83092c62016-01-11 17:00:36 -0800628}