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