1 package com.android.systemui.statusbar.phone;
2 
3 import android.content.Context;
4 import android.content.res.Resources;
5 import android.graphics.Color;
6 import android.graphics.Rect;
7 import android.view.LayoutInflater;
8 import android.view.View;
9 import android.view.ViewGroup;
10 import android.widget.FrameLayout;
11 
12 import androidx.annotation.NonNull;
13 import androidx.collection.ArrayMap;
14 
15 import com.android.internal.statusbar.StatusBarIcon;
16 import com.android.internal.util.ContrastColorUtil;
17 import com.android.settingslib.Utils;
18 import com.android.systemui.Dependency;
19 import com.android.systemui.Interpolators;
20 import com.android.systemui.R;
21 import com.android.systemui.plugins.DarkIconDispatcher;
22 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
23 import com.android.systemui.plugins.statusbar.StatusBarStateController;
24 import com.android.systemui.statusbar.CrossFadeHelper;
25 import com.android.systemui.statusbar.NotificationMediaManager;
26 import com.android.systemui.statusbar.NotificationShelf;
27 import com.android.systemui.statusbar.StatusBarIconView;
28 import com.android.systemui.statusbar.StatusBarState;
29 import com.android.systemui.statusbar.notification.NotificationEntryManager;
30 import com.android.systemui.statusbar.notification.NotificationUtils;
31 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
32 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
33 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
34 
35 import java.util.ArrayList;
36 import java.util.Objects;
37 import java.util.function.Function;
38 
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  */
43 public class NotificationIconAreaController implements DarkReceiver,
44         StatusBarStateController.StateListener,
45         NotificationWakeUpCoordinator.WakeUpListener {
46 
47     public static final String HIGH_PRIORITY = "high_priority";
48     private static final long AOD_ICONS_APPEAR_DURATION = 200;
49 
50     private final ContrastColorUtil mContrastColorUtil;
51     private final NotificationEntryManager mEntryManager;
52     private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
53     private final StatusBarStateController mStatusBarStateController;
54     private final NotificationMediaManager mMediaManager;
55     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
56     private final KeyguardBypassController mBypassController;
57     private final DozeParameters mDozeParameters;
58 
59     private int mIconSize;
60     private int mIconHPadding;
61     private int mIconTint = Color.WHITE;
62     private int mCenteredIconTint = Color.WHITE;
63 
64     private StatusBar mStatusBar;
65     protected View mNotificationIconArea;
66     private NotificationIconContainer mNotificationIcons;
67     private NotificationIconContainer mShelfIcons;
68     protected View mCenteredIconArea;
69     private NotificationIconContainer mCenteredIcon;
70     private NotificationIconContainer mAodIcons;
71     private StatusBarIconView mCenteredIconView;
72     private final Rect mTintArea = new Rect();
73     private ViewGroup mNotificationScrollLayout;
74     private Context mContext;
75     private int mAodIconAppearTranslation;
76 
77     private boolean mAnimationsEnabled;
78     private int mAodIconTint;
79     private boolean mFullyHidden;
80     private boolean mAodIconsVisible;
81     private boolean mIsPulsing;
82 
NotificationIconAreaController(Context context, StatusBar statusBar, StatusBarStateController statusBarStateController, NotificationWakeUpCoordinator wakeUpCoordinator, KeyguardBypassController keyguardBypassController, NotificationMediaManager notificationMediaManager)83     public NotificationIconAreaController(Context context, StatusBar statusBar,
84             StatusBarStateController statusBarStateController,
85             NotificationWakeUpCoordinator wakeUpCoordinator,
86             KeyguardBypassController keyguardBypassController,
87             NotificationMediaManager notificationMediaManager) {
88         mStatusBar = statusBar;
89         mContrastColorUtil = ContrastColorUtil.getInstance(context);
90         mContext = context;
91         mEntryManager = Dependency.get(NotificationEntryManager.class);
92         mStatusBarStateController = statusBarStateController;
93         mStatusBarStateController.addCallback(this);
94         mMediaManager = notificationMediaManager;
95         mDozeParameters = DozeParameters.getInstance(mContext);
96         mWakeUpCoordinator = wakeUpCoordinator;
97         wakeUpCoordinator.addListener(this);
98         mBypassController = keyguardBypassController;
99 
100         initializeNotificationAreaViews(context);
101         reloadAodColor();
102     }
103 
inflateIconArea(LayoutInflater inflater)104     protected View inflateIconArea(LayoutInflater inflater) {
105         return inflater.inflate(R.layout.notification_icon_area, null);
106     }
107 
108     /**
109      * Initializes the views that will represent the notification area.
110      */
initializeNotificationAreaViews(Context context)111     protected void initializeNotificationAreaViews(Context context) {
112         reloadDimens(context);
113 
114         LayoutInflater layoutInflater = LayoutInflater.from(context);
115         mNotificationIconArea = inflateIconArea(layoutInflater);
116         mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);
117 
118         mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
119 
120         mCenteredIconArea = layoutInflater.inflate(R.layout.center_icon_area, null);
121         mCenteredIcon = mCenteredIconArea.findViewById(R.id.centeredIcon);
122 
123         initAodIcons();
124     }
125 
initAodIcons()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);
135         updateAodIconsVisibility(false /* animate */);
136         updateAnimations();
137         if (changed) {
138             updateAodNotificationIcons();
139         }
140     }
141 
setupShelf(NotificationShelf shelf)142     public void setupShelf(NotificationShelf shelf) {
143         mShelfIcons = shelf.getShelfIcons();
144         shelf.setCollapsedIcons(mNotificationIcons);
145     }
146 
onDensityOrFontScaleChanged(Context context)147     public void onDensityOrFontScaleChanged(Context context) {
148         reloadDimens(context);
149         final FrameLayout.LayoutParams params = generateIconLayoutParams();
150         for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
151             View child = mNotificationIcons.getChildAt(i);
152             child.setLayoutParams(params);
153         }
154         for (int i = 0; i < mShelfIcons.getChildCount(); i++) {
155             View child = mShelfIcons.getChildAt(i);
156             child.setLayoutParams(params);
157         }
158         for (int i = 0; i < mCenteredIcon.getChildCount(); i++) {
159             View child = mCenteredIcon.getChildAt(i);
160             child.setLayoutParams(params);
161         }
162         for (int i = 0; i < mAodIcons.getChildCount(); i++) {
163             View child = mAodIcons.getChildAt(i);
164             child.setLayoutParams(params);
165         }
166     }
167 
168     @NonNull
generateIconLayoutParams()169     private FrameLayout.LayoutParams generateIconLayoutParams() {
170         return new FrameLayout.LayoutParams(
171                 mIconSize + 2 * mIconHPadding, getHeight());
172     }
173 
reloadDimens(Context context)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);
178         mAodIconAppearTranslation = res.getDimensionPixelSize(
179                 R.dimen.shelf_appear_translation);
180     }
181 
182     /**
183      * Returns the view that represents the notification area.
184      */
getNotificationInnerAreaView()185     public View getNotificationInnerAreaView() {
186         return mNotificationIconArea;
187     }
188 
189     /**
190      * Returns the view that represents the centered notification area.
191      */
getCenteredNotificationAreaView()192     public View getCenteredNotificationAreaView() {
193         return mCenteredIconArea;
194     }
195 
196     /**
197      * 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.
199      *
200      * @param tintArea the area in which to tint the icons, specified in screen coordinates
201      * @param darkIntensity
202      */
onDarkChanged(Rect tintArea, float darkIntensity, int iconTint)203     public void onDarkChanged(Rect tintArea, float darkIntensity, int iconTint) {
204         if (tintArea == null) {
205             mTintArea.setEmpty();
206         } else {
207             mTintArea.set(tintArea);
208         }
209 
210         if (mNotificationIconArea != null) {
211             if (DarkIconDispatcher.isInArea(tintArea, mNotificationIconArea)) {
212                 mIconTint = iconTint;
213             }
214         } else {
215             mIconTint = iconTint;
216         }
217 
218         if (mCenteredIconArea != null) {
219             if (DarkIconDispatcher.isInArea(tintArea, mCenteredIconArea)) {
220                 mCenteredIconTint = iconTint;
221             }
222         } else {
223             mCenteredIconTint = iconTint;
224         }
225 
226         applyNotificationIconsTint();
227     }
228 
getHeight()229     protected int getHeight() {
230         return mStatusBar.getStatusBarHeight();
231     }
232 
shouldShowNotificationIcon(NotificationEntry entry, boolean showAmbient, boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon, boolean hidePulsing, boolean onlyShowCenteredIcon)233     protected boolean shouldShowNotificationIcon(NotificationEntry entry,
234             boolean showAmbient, boolean hideDismissed,
235             boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon,
236             boolean hidePulsing, boolean onlyShowCenteredIcon) {
237 
238         final boolean isCenteredNotificationIcon = mCenteredIconView != null
239                 && entry.centeredIcon != null
240                 && Objects.equals(entry.centeredIcon, mCenteredIconView);
241         if (onlyShowCenteredIcon) {
242             return isCenteredNotificationIcon;
243         }
244         if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
245             return false;
246         }
247         if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
248             return false;
249         }
250         if (hideCurrentMedia && entry.key.equals(mMediaManager.getMediaNotificationKey())) {
251             return false;
252         }
253         if (!entry.isTopLevelChild()) {
254             return false;
255         }
256         if (entry.getRow().getVisibility() == View.GONE) {
257             return false;
258         }
259         if (entry.isRowDismissed() && hideDismissed) {
260             return false;
261         }
262         if (hideRepliedMessages && entry.isLastMessageFromReply()) {
263             return false;
264         }
265         // showAmbient == show in shade but not shelf
266         if (!showAmbient && entry.shouldSuppressStatusBar()) {
267             return false;
268         }
269         if (hidePulsing && entry.showingPulsing()
270                 && (!mWakeUpCoordinator.getNotificationsFullyHidden()
271                         || !entry.isPulseSuppressed())) {
272             return false;
273         }
274         return true;
275     }
276 
277     /**
278      * Updates the notifications with the given list of notifications to display.
279      */
updateNotificationIcons()280     public void updateNotificationIcons() {
281         updateStatusBarIcons();
282         updateShelfIcons();
283         updateCenterIcon();
284         updateAodNotificationIcons();
285 
286         applyNotificationIconsTint();
287     }
288 
updateShelfIcons()289     private void updateShelfIcons() {
290         updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
291                 true /* showAmbient */,
292                 false /* hideDismissed */,
293                 false /* hideRepliedMessages */,
294                 false /* hideCurrentMedia */,
295                 false /* hide centered icon */,
296                 false /* hidePulsing */,
297                 false /* onlyShowCenteredIcon */);
298     }
299 
updateStatusBarIcons()300     public void updateStatusBarIcons() {
301         updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
302                 false /* showAmbient */,
303                 true /* hideDismissed */,
304                 true /* hideRepliedMessages */,
305                 false /* hideCurrentMedia */,
306                 true /* hide centered icon */,
307                 false /* hidePulsing */,
308                 false /* onlyShowCenteredIcon */);
309     }
310 
updateCenterIcon()311     private void updateCenterIcon() {
312         updateIconsForLayout(entry -> entry.centeredIcon, mCenteredIcon,
313                 false /* showAmbient */,
314                 false /* hideDismissed */,
315                 false /* hideRepliedMessages */,
316                 false /* hideCurrentMedia */,
317                 false /* hide centered icon */,
318                 false /* hidePulsing */,
319                 true/* onlyShowCenteredIcon */);
320     }
321 
updateAodNotificationIcons()322     public void updateAodNotificationIcons() {
323         updateIconsForLayout(entry -> entry.aodIcon, mAodIcons,
324                 false /* showAmbient */,
325                 true /* hideDismissed */,
326                 true /* hideRepliedMessages */,
327                 true /* hideCurrentMedia */,
328                 true /* hide centered icon */,
329                 mBypassController.getBypassEnabled() /* hidePulsing */,
330                 false /* onlyShowCenteredIcon */);
331     }
332 
333     /**
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.
336      * @param function A function to look up an icon view based on an entry
337      * @param hostLayout which layout should be updated
338      * @param showAmbient should ambient notification icons be shown
339      * @param hideDismissed should dismissed icons be hidden
340      * @param hideRepliedMessages should messages that have been replied to be hidden
341      * @param hidePulsing should pulsing notifications be hidden
342      */
updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function, NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon, boolean hidePulsing, boolean onlyShowCenteredIcon)343     private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
344             NotificationIconContainer hostLayout, boolean showAmbient,
345             boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia,
346             boolean hideCenteredIcon, boolean hidePulsing, boolean onlyShowCenteredIcon) {
347         ArrayList<StatusBarIconView> toShow = new ArrayList<>(
348                 mNotificationScrollLayout.getChildCount());
349 
350         // Filter out ambient notifications and notification children.
351         for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
352             View view = mNotificationScrollLayout.getChildAt(i);
353             if (view instanceof ExpandableNotificationRow) {
354                 NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
355                 if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
356                         hideRepliedMessages, hideCurrentMedia, hideCenteredIcon, hidePulsing,
357                         onlyShowCenteredIcon)) {
358                     StatusBarIconView iconView = function.apply(ent);
359                     if (iconView != null) {
360                         toShow.add(iconView);
361                     }
362                 }
363             }
364         }
365 
366         // 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.
369 
370         ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons = new ArrayMap<>();
371         ArrayList<View> toRemove = new ArrayList<>();
372         for (int i = 0; i < hostLayout.getChildCount(); i++) {
373             View child = hostLayout.getChildAt(i);
374             if (!(child instanceof StatusBarIconView)) {
375                 continue;
376             }
377             if (!toShow.contains(child)) {
378                 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);
402             }
403         }
404         // 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);
414 
415         final int toRemoveCount = toRemove.size();
416         for (int i = 0; i < toRemoveCount; i++) {
417             hostLayout.removeView(toRemove.get(i));
418         }
419 
420         final FrameLayout.LayoutParams params = generateIconLayoutParams();
421         for (int i = 0; i < toShow.size(); i++) {
422             StatusBarIconView v = toShow.get(i);
423             // The view might still be transiently added if it was just removed and added again
424             hostLayout.removeTransientView(v);
425             if (v.getParent() == null) {
426                 if (hideDismissed) {
427                     v.setOnDismissListener(mUpdateStatusBarIcons);
428                 }
429                 hostLayout.addView(v, i, params);
430             }
431         }
432 
433         hostLayout.setChangingViewPositions(true);
434         // Re-sort notification icons
435         final int childCount = hostLayout.getChildCount();
436         for (int i = 0; i < childCount; i++) {
437             View actual = hostLayout.getChildAt(i);
438             StatusBarIconView expected = toShow.get(i);
439             if (actual == expected) {
440                 continue;
441             }
442             hostLayout.removeView(expected);
443             hostLayout.addView(expected, i);
444         }
445         hostLayout.setChangingViewPositions(false);
446         hostLayout.setReplacingIcons(null);
447     }
448 
449     /**
450      * Applies {@link #mIconTint} to the notification icons.
451      * Applies {@link #mCenteredIconTint} to the center notification icon.
452      */
applyNotificationIconsTint()453     private void applyNotificationIconsTint() {
454         for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
455             final StatusBarIconView iv = (StatusBarIconView) mNotificationIcons.getChildAt(i);
456             if (iv.getWidth() != 0) {
457                 updateTintForIcon(iv, mIconTint);
458             } else {
459                 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));
469             }
470         }
471 
472         updateAodIconColors();
473     }
474 
updateTintForIcon(StatusBarIconView v, int tint)475     private void updateTintForIcon(StatusBarIconView v, int tint) {
476         boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
477         int color = StatusBarIconView.NO_COLOR;
478         boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mContrastColorUtil);
479         if (colorize) {
480             color = DarkIconDispatcher.getTint(mTintArea, v, tint);
481         }
482         v.setStaticDrawableColor(color);
483         v.setDecorColor(tint);
484     }
485 
486     /**
487      * Shows the icon view given in the center.
488      */
showIconCentered(NotificationEntry entry)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         }
495     }
496 
showIconIsolated(StatusBarIconView icon, boolean animated)497     public void showIconIsolated(StatusBarIconView icon, boolean animated) {
498         mNotificationIcons.showIconIsolated(icon, animated);
499     }
500 
setIsolatedIconLocation(Rect iconDrawingRect, boolean requireStateUpdate)501     public void setIsolatedIconLocation(Rect iconDrawingRect, boolean requireStateUpdate) {
502         mNotificationIcons.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate);
503     }
504 
505     @Override
onDozingChanged(boolean isDozing)506     public void onDozingChanged(boolean isDozing) {
507         boolean animate = mDozeParameters.getAlwaysOn()
508                 && !mDozeParameters.getDisplayNeedsBlanking();
509         mAodIcons.setDozing(isDozing, animate, 0);
510     }
511 
setAnimationsEnabled(boolean enabled)512     public void setAnimationsEnabled(boolean enabled) {
513         mAnimationsEnabled = enabled;
514         updateAnimations();
515     }
516 
517     @Override
onStateChanged(int newState)518     public void onStateChanged(int newState) {
519         updateAodIconsVisibility(false /* animate */);
520         updateAnimations();
521     }
522 
updateAnimations()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 
onThemeChanged()530     public void onThemeChanged() {
531         reloadAodColor();
532         updateAodIconColors();
533     }
534 
appearAodIcons()535     public void appearAodIcons() {
536         DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
537         if (dozeParameters.shouldControlScreenOff()) {
538             mAodIcons.setTranslationY(-mAodIconAppearTranslation);
539             mAodIcons.setAlpha(0);
540             animateInAodIconTranslation();
541             mAodIcons.animate()
542                     .alpha(1)
543                     .setInterpolator(Interpolators.LINEAR)
544                     .setDuration(AOD_ICONS_APPEAR_DURATION)
545                     .start();
546         }
547     }
548 
animateInAodIconTranslation()549     private void animateInAodIconTranslation() {
550         mAodIcons.animate()
551                 .setInterpolator(Interpolators.DECELERATE_QUINT)
552                 .translationY(0)
553                 .setDuration(AOD_ICONS_APPEAR_DURATION)
554                 .start();
555     }
556 
reloadAodColor()557     private void reloadAodColor() {
558         mAodIconTint = Utils.getColorAttrDefaultColor(mContext,
559                 R.attr.wallpaperTextColor);
560     }
updateAodIconColors()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 
572     @Override
onFullyHiddenChanged(boolean fullyHidden)573     public void onFullyHiddenChanged(boolean fullyHidden) {
574         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;
580         }
581         updateAodIconsVisibility(animate);
582         updateAodNotificationIcons();
583     }
584 
585     @Override
onPulseExpansionChanged(boolean expandingChanged)586     public void onPulseExpansionChanged(boolean expandingChanged) {
587         if (expandingChanged) {
588             updateAodIconsVisibility(true /* animate */);
589         }
590     }
591 
updateAodIconsVisibility(boolean animate)592     private void updateAodIconsVisibility(boolean animate) {
593         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         }
601         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 {
613                         // Let's make sure the icon are translated to 0, since we cancelled it above
614                         animateInAodIconTranslation();
615                         // We were fading out, let's fade in instead
616                         CrossFadeHelper.fadeIn(mAodIcons);
617                     }
618                 } else {
619                     // Let's make sure the icon are translated to 0, since we cancelled it above
620                     animateInAodIconTranslation();
621                     CrossFadeHelper.fadeOut(mAodIcons);
622                 }
623             } else {
624                 mAodIcons.setAlpha(1.0f);
625                 mAodIcons.setTranslationY(0);
626                 mAodIcons.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
627             }
628         }
629     }
630 }
631