1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.notification.collection.coordinator; 18 19 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; 20 21 import androidx.annotation.NonNull; 22 import androidx.annotation.VisibleForTesting; 23 24 import com.android.systemui.Dumpable; 25 import com.android.systemui.Flags; 26 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor; 27 import com.android.systemui.dagger.SysUISingleton; 28 import com.android.systemui.dagger.qualifiers.Background; 29 import com.android.systemui.dagger.qualifiers.Main; 30 import com.android.systemui.dump.DumpManager; 31 import com.android.systemui.keyguard.WakefulnessLifecycle; 32 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; 33 import com.android.systemui.keyguard.shared.model.Edge; 34 import com.android.systemui.keyguard.shared.model.KeyguardState; 35 import com.android.systemui.plugins.statusbar.StatusBarStateController; 36 import com.android.systemui.scene.shared.flag.SceneContainerFlag; 37 import com.android.systemui.scene.shared.model.Scenes; 38 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor; 39 import com.android.systemui.shade.domain.interactor.ShadeInteractor; 40 import com.android.systemui.statusbar.notification.VisibilityLocationProvider; 41 import com.android.systemui.statusbar.notification.collection.GroupEntry; 42 import com.android.systemui.statusbar.notification.collection.NotifPipeline; 43 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 44 import com.android.systemui.statusbar.notification.collection.PipelineEntry; 45 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; 46 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; 47 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; 48 import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository; 49 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor; 50 import com.android.systemui.statusbar.notification.shared.NotificationMinimalism; 51 import com.android.systemui.statusbar.policy.KeyguardStateController; 52 import com.android.systemui.util.concurrency.DelayableExecutor; 53 import com.android.systemui.util.kotlin.BooleanFlowOperators; 54 import com.android.systemui.util.kotlin.JavaAdapter; 55 56 import java.io.PrintWriter; 57 import java.util.HashMap; 58 import java.util.HashSet; 59 import java.util.List; 60 import java.util.Map; 61 import java.util.Set; 62 63 import javax.inject.Inject; 64 65 /** 66 * Ensures that notifications are visually stable if the user is looking at the notifications. 67 * Group and section changes are re-allowed when the notification entries are no longer being 68 * viewed. 69 */ 70 // TODO(b/204468557): Move to @CoordinatorScope 71 @SysUISingleton 72 public class VisualStabilityCoordinator implements Coordinator, Dumpable { 73 private final DelayableExecutor mDelayableExecutor; 74 private final DelayableExecutor mMainExecutor; 75 private final HeadsUpRepository mHeadsUpRepository; 76 private final SeenNotificationsInteractor mSeenNotificationsInteractor; 77 private final ShadeAnimationInteractor mShadeAnimationInteractor; 78 private final StatusBarStateController mStatusBarStateController; 79 private final JavaAdapter mJavaAdapter; 80 private final VisibilityLocationProvider mVisibilityLocationProvider; 81 private final VisualStabilityProvider mVisualStabilityProvider; 82 private final WakefulnessLifecycle mWakefulnessLifecycle; 83 private final CommunalSceneInteractor mCommunalSceneInteractor; 84 private final ShadeInteractor mShadeInteractor; 85 private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; 86 private final KeyguardStateController mKeyguardStateController; 87 private final VisualStabilityCoordinatorLogger mLogger; 88 89 private boolean mSleepy = true; 90 private boolean mFullyDozed; 91 private boolean mPanelExpanded; 92 private boolean mPulsing; 93 private boolean mNotifPanelCollapsing; 94 private boolean mNotifPanelLaunchingActivity; 95 private boolean mCommunalShowing = false; 96 private boolean mLockscreenShowing = false; 97 private boolean mTrackingHeadsUp = false; 98 private boolean mLockscreenInGoneTransition = false; 99 private Set<String> mHeadsUpGroupKeys = new HashSet<>(); 100 101 private boolean mPipelineRunAllowed; 102 private boolean mReorderingAllowed; 103 private boolean mIsSuppressingPipelineRun = false; 104 private boolean mIsSuppressingGroupChange = false; 105 private final Set<String> mEntriesWithSuppressedSectionChange = new HashSet<>(); 106 private boolean mIsSuppressingEntryReorder = false; 107 108 // key: notification key that can temporarily change its section 109 // value: runnable that when run removes its associated RemoveOverrideSuppressionRunnable 110 // from the DelayableExecutor's queue 111 private Map<String, Runnable> mEntriesThatCanChangeSection = new HashMap<>(); 112 113 @VisibleForTesting 114 protected static final long ALLOW_SECTION_CHANGE_TIMEOUT = 500; 115 116 private final boolean mCheckLockScreenTransitionEnabled = Flags.checkLockscreenGoneTransition(); 117 118 @Inject VisualStabilityCoordinator( @ackground DelayableExecutor delayableExecutor, @Main DelayableExecutor mainExecutor, DumpManager dumpManager, HeadsUpRepository headsUpRepository, ShadeAnimationInteractor shadeAnimationInteractor, JavaAdapter javaAdapter, SeenNotificationsInteractor seenNotificationsInteractor, StatusBarStateController statusBarStateController, VisibilityLocationProvider visibilityLocationProvider, VisualStabilityProvider visualStabilityProvider, WakefulnessLifecycle wakefulnessLifecycle, CommunalSceneInteractor communalSceneInteractor, ShadeInteractor shadeInteractor, KeyguardTransitionInteractor keyguardTransitionInteractor, KeyguardStateController keyguardStateController, VisualStabilityCoordinatorLogger logger)119 public VisualStabilityCoordinator( 120 @Background DelayableExecutor delayableExecutor, 121 @Main DelayableExecutor mainExecutor, 122 DumpManager dumpManager, 123 HeadsUpRepository headsUpRepository, 124 ShadeAnimationInteractor shadeAnimationInteractor, 125 JavaAdapter javaAdapter, 126 SeenNotificationsInteractor seenNotificationsInteractor, 127 StatusBarStateController statusBarStateController, 128 VisibilityLocationProvider visibilityLocationProvider, 129 VisualStabilityProvider visualStabilityProvider, 130 WakefulnessLifecycle wakefulnessLifecycle, 131 CommunalSceneInteractor communalSceneInteractor, 132 ShadeInteractor shadeInteractor, 133 KeyguardTransitionInteractor keyguardTransitionInteractor, 134 KeyguardStateController keyguardStateController, 135 VisualStabilityCoordinatorLogger logger) { 136 mHeadsUpRepository = headsUpRepository; 137 mShadeAnimationInteractor = shadeAnimationInteractor; 138 mJavaAdapter = javaAdapter; 139 mSeenNotificationsInteractor = seenNotificationsInteractor; 140 mVisibilityLocationProvider = visibilityLocationProvider; 141 mVisualStabilityProvider = visualStabilityProvider; 142 mWakefulnessLifecycle = wakefulnessLifecycle; 143 mStatusBarStateController = statusBarStateController; 144 mDelayableExecutor = delayableExecutor; 145 mMainExecutor = mainExecutor; 146 mCommunalSceneInteractor = communalSceneInteractor; 147 mShadeInteractor = shadeInteractor; 148 mKeyguardTransitionInteractor = keyguardTransitionInteractor; 149 mKeyguardStateController = keyguardStateController; 150 mLogger = logger; 151 152 dumpManager.registerDumpable(this); 153 } 154 155 @Override attach(NotifPipeline pipeline)156 public void attach(NotifPipeline pipeline) { 157 mWakefulnessLifecycle.addObserver(mWakefulnessObserver); 158 mSleepy = mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP; 159 mFullyDozed = mStatusBarStateController.getDozeAmount() == 1f; 160 161 mStatusBarStateController.addCallback(mStatusBarStateControllerListener); 162 mPulsing = mStatusBarStateController.isPulsing(); 163 mJavaAdapter.alwaysCollectFlow(mShadeAnimationInteractor.isAnyCloseAnimationRunning(), 164 this::onShadeOrQsClosingChanged); 165 mJavaAdapter.alwaysCollectFlow(mShadeAnimationInteractor.isLaunchingActivity(), 166 this::onLaunchingActivityChanged); 167 mJavaAdapter.alwaysCollectFlow( 168 BooleanFlowOperators.INSTANCE.allOf( 169 mCommunalSceneInteractor.isIdleOnCommunal(), 170 BooleanFlowOperators.INSTANCE.not(mShadeInteractor.isAnyFullyExpanded()) 171 ), 172 this::onCommunalShowingChanged); 173 174 175 if (StabilizeHeadsUpGroup.isEnabled()) { 176 pipeline.addOnBeforeRenderListListener(mOnBeforeRenderListListener); 177 } 178 179 if (SceneContainerFlag.isEnabled()) { 180 mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.transitionValue( 181 KeyguardState.LOCKSCREEN), 182 this::onLockscreenKeyguardStateTransitionValueChanged); 183 mJavaAdapter.alwaysCollectFlow(mHeadsUpRepository.isTrackingHeadsUp(), 184 this::onTrackingHeadsUpModeChanged); 185 } 186 187 if (mCheckLockScreenTransitionEnabled) { 188 if (SceneContainerFlag.isEnabled()) { 189 mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.isInTransition( 190 Edge.create(KeyguardState.LOCKSCREEN, Scenes.Gone), null), 191 this::onLockscreenInGoneTransitionChanged); 192 } else { 193 mKeyguardStateController.addCallback(mKeyguardFadeAwayAnimationCallback); 194 } 195 } 196 pipeline.setVisualStabilityManager(mNotifStabilityManager); 197 } 198 199 /** 200 * Setter of heads up group keys. 201 */ 202 @VisibleForTesting setHeadsUpGroupKeys(Set<String> currentHeadsUpGroupKeys)203 public void setHeadsUpGroupKeys(Set<String> currentHeadsUpGroupKeys) { 204 if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) { 205 return; 206 } 207 208 if (currentHeadsUpGroupKeys == null) { 209 currentHeadsUpGroupKeys = new HashSet<>(); 210 } 211 212 boolean isAnyHeadsUpGroupRemoved = false; 213 for (String headsUpKey: mHeadsUpGroupKeys) { 214 if (!currentHeadsUpGroupKeys.contains(headsUpKey)) { 215 isAnyHeadsUpGroupRemoved = true; 216 break; 217 } 218 } 219 mHeadsUpGroupKeys = currentHeadsUpGroupKeys; 220 221 if (isAnyHeadsUpGroupRemoved) { 222 updateAllowedStates("headsUpGroupEntryChange", 223 mHeadsUpGroupKeys.isEmpty(), /* async= */ true); 224 } 225 } 226 227 final KeyguardStateController.Callback mKeyguardFadeAwayAnimationCallback = 228 new KeyguardStateController.Callback() { 229 @Override 230 public void onKeyguardFadingAwayChanged() { 231 onLockscreenInGoneTransitionChanged( 232 mKeyguardStateController.isKeyguardFadingAway()); 233 } 234 }; 235 236 // TODO(b/203826051): Ensure stability manager can allow reordering off-screen 237 // HUNs to the top of the shade 238 private final NotifStabilityManager mNotifStabilityManager = 239 new NotifStabilityManager("VisualStabilityCoordinator") { 240 private boolean canMoveForHeadsUp(NotificationEntry entry) { 241 if (entry == null) { 242 return false; 243 } 244 boolean isTopUnseen = NotificationMinimalism.isEnabled() 245 && (mSeenNotificationsInteractor.isTopUnseenNotification(entry) 246 || mSeenNotificationsInteractor.isTopOngoingNotification(entry)); 247 if (isTopUnseen || mHeadsUpRepository.isHeadsUpEntry(entry.getKey())) { 248 return !mVisibilityLocationProvider.isInVisibleLocation(entry); 249 } 250 return false; 251 } 252 253 private boolean isParentHeadsUpGroup(NotificationEntry entry) { 254 if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) { 255 return false; 256 } 257 if (entry == null) { 258 return false; 259 } 260 261 final PipelineEntry parent = entry.getParent(); 262 263 if (parent == null) { 264 return false; 265 } 266 return isHeadsUpGroup(parent); 267 } 268 269 private boolean isHeadsUpGroup(PipelineEntry pipelineEntry) { 270 if (!(pipelineEntry instanceof GroupEntry groupEntry)) { 271 return false; 272 } 273 274 if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) { 275 return false; 276 } 277 278 final NotificationEntry summary = groupEntry.getSummary(); 279 if (summary == null) { 280 return false; 281 } 282 283 return mHeadsUpRepository.isHeadsUpEntry(summary.getKey()); 284 } 285 /** 286 * When reordering is enabled, non-heads-up groups can be pruned. 287 * @return true if the given group entry can be pruned. 288 */ 289 private boolean canReorderGroupEntry(GroupEntry entry) { 290 if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) { 291 return false; 292 } 293 294 return entry != null && mReorderingAllowed && !isHeadsUpGroup(entry); 295 } 296 297 /** 298 * When reordering is enabled, notifications in non-heads-up groups notifications 299 * are allowed to change. 300 * @return true if the given notification entry can changed. 301 */ 302 private boolean canReorderNotificationEntry(NotificationEntry entry) { 303 if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) { 304 return false; 305 } 306 307 return entry != null && mReorderingAllowed && !isParentHeadsUpGroup(entry); 308 } 309 310 @Override 311 public void onBeginRun() { 312 mIsSuppressingPipelineRun = false; 313 mIsSuppressingGroupChange = false; 314 mEntriesWithSuppressedSectionChange.clear(); 315 mIsSuppressingEntryReorder = false; 316 } 317 318 @Override 319 public boolean isPipelineRunAllowed() { 320 mIsSuppressingPipelineRun |= !mPipelineRunAllowed; 321 return mPipelineRunAllowed; 322 } 323 324 @Override 325 public boolean isGroupChangeAllowed(@NonNull NotificationEntry entry) { 326 final boolean isGroupChangeAllowedForEntry; 327 if (StabilizeHeadsUpGroup.isEnabled()) { 328 isGroupChangeAllowedForEntry = 329 isEveryChangeAllowed() 330 || canReorderNotificationEntry(entry) 331 || canMoveForHeadsUp(entry); 332 } else { 333 isGroupChangeAllowedForEntry = mReorderingAllowed 334 || canMoveForHeadsUp(entry); 335 } 336 mIsSuppressingGroupChange |= !isGroupChangeAllowedForEntry; 337 return isGroupChangeAllowedForEntry; 338 } 339 340 @Override 341 public boolean isGroupPruneAllowed(@NonNull GroupEntry entry) { 342 boolean isGroupPruneAllowedForEntry; 343 if (StabilizeHeadsUpGroup.isEnabled()) { 344 isGroupPruneAllowedForEntry = isEveryChangeAllowed() 345 || canReorderGroupEntry(entry); 346 } else { 347 isGroupPruneAllowedForEntry = mReorderingAllowed; 348 } 349 350 mIsSuppressingGroupChange |= !isGroupPruneAllowedForEntry; 351 return isGroupPruneAllowedForEntry; 352 } 353 354 @Override 355 public boolean isSectionChangeAllowed(@NonNull NotificationEntry entry) { 356 final boolean isSectionChangeAllowedForEntry; 357 if (StabilizeHeadsUpGroup.isEnabled()) { 358 isSectionChangeAllowedForEntry = 359 isEveryChangeAllowed() 360 || canReorderNotificationEntry(entry) 361 || canMoveForHeadsUp(entry) 362 || mEntriesThatCanChangeSection.containsKey(entry.getKey()); 363 } else { 364 isSectionChangeAllowedForEntry = 365 mReorderingAllowed 366 || canMoveForHeadsUp(entry) 367 || mEntriesThatCanChangeSection.containsKey(entry.getKey()); 368 } 369 370 if (!isSectionChangeAllowedForEntry) { 371 mEntriesWithSuppressedSectionChange.add(entry.getKey()); 372 } 373 return isSectionChangeAllowedForEntry; 374 } 375 376 @Override 377 public boolean isEntryReorderingAllowed(@NonNull PipelineEntry entry) { 378 if (StabilizeHeadsUpGroup.isEnabled()) { 379 if (isEveryChangeAllowed()) { 380 return true; 381 } 382 383 final NotificationEntry notificationEntry = entry.getRepresentativeEntry(); 384 return canReorderNotificationEntry(notificationEntry) 385 || canMoveForHeadsUp(notificationEntry); 386 } else { 387 return mReorderingAllowed || canMoveForHeadsUp( 388 entry.getRepresentativeEntry()); 389 } 390 } 391 392 @Override 393 public boolean isEveryChangeAllowed() { 394 if (StabilizeHeadsUpGroup.isEnabled()) { 395 return mReorderingAllowed && mHeadsUpGroupKeys.isEmpty(); 396 } else { 397 return mReorderingAllowed; 398 } 399 } 400 401 @Override 402 public void onEntryReorderSuppressed() { 403 mIsSuppressingEntryReorder = true; 404 } 405 }; 406 407 private final OnBeforeRenderListListener mOnBeforeRenderListListener = 408 new OnBeforeRenderListListener() { 409 @Override 410 public void onBeforeRenderList(List<PipelineEntry> entries) { 411 if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) { 412 return; 413 } 414 415 final Set<String> currentHeadsUpKeys = new HashSet<>(); 416 417 for (int i = 0; i < entries.size(); i++) { 418 if (entries.get(i) instanceof GroupEntry groupEntry) { 419 final NotificationEntry summary = groupEntry.getSummary(); 420 if (summary == null) continue; 421 422 final String summaryKey = summary.getKey(); 423 if (mHeadsUpRepository.isHeadsUpEntry(summaryKey)) { 424 currentHeadsUpKeys.add(summaryKey); 425 } 426 } 427 } 428 429 setHeadsUpGroupKeys(currentHeadsUpKeys); 430 } 431 }; 432 updateAllowedStates(String field, boolean value)433 private void updateAllowedStates(String field, boolean value) { 434 updateAllowedStates(field, value, /* async = */ false); 435 } 436 updateAllowedStates(String field, boolean value, boolean async)437 private void updateAllowedStates(String field, boolean value, boolean async) { 438 boolean wasPipelineRunAllowed = mPipelineRunAllowed; 439 boolean wasReorderingAllowed = mReorderingAllowed; 440 // No need to run notification pipeline when the lockscreen is in fading animation. 441 mPipelineRunAllowed = !(isPanelCollapsingOrLaunchingActivity() 442 || (mCheckLockScreenTransitionEnabled && mLockscreenInGoneTransition)); 443 mReorderingAllowed = isReorderingAllowed(); 444 if (wasPipelineRunAllowed != mPipelineRunAllowed 445 || wasReorderingAllowed != mReorderingAllowed) { 446 mLogger.logAllowancesChanged( 447 wasPipelineRunAllowed, mPipelineRunAllowed, 448 wasReorderingAllowed, mReorderingAllowed, 449 field, value, async); 450 } 451 if (async) { 452 mMainExecutor.execute(this::maybeInvalidateList); 453 } else { 454 maybeInvalidateList(); 455 } 456 mVisualStabilityProvider.setReorderingAllowed(mReorderingAllowed); 457 } 458 maybeInvalidateList()459 private void maybeInvalidateList() { 460 if (mPipelineRunAllowed && mIsSuppressingPipelineRun) { 461 mNotifStabilityManager.invalidateList("pipeline run suppression ended"); 462 } else if (mReorderingAllowed && (mIsSuppressingGroupChange 463 || isSuppressingSectionChange() 464 || mIsSuppressingEntryReorder)) { 465 final String reason = "reorder suppression ended for" 466 + " group=" + mIsSuppressingGroupChange 467 + " section=" + isSuppressingSectionChange() 468 + " sort=" + mIsSuppressingEntryReorder; 469 mNotifStabilityManager.invalidateList(reason); 470 } 471 } 472 isSuppressingSectionChange()473 private boolean isSuppressingSectionChange() { 474 return !mEntriesWithSuppressedSectionChange.isEmpty(); 475 } 476 isPanelCollapsingOrLaunchingActivity()477 private boolean isPanelCollapsingOrLaunchingActivity() { 478 return mNotifPanelCollapsing || mNotifPanelLaunchingActivity; 479 } 480 isReorderingAllowed()481 private boolean isReorderingAllowed() { 482 final boolean sleepyAndDozed = mFullyDozed && mSleepy; 483 final boolean stackShowing = isStackShowing(); 484 return (sleepyAndDozed || !stackShowing || mCommunalShowing) && !mPulsing; 485 } 486 487 /** @return true when the notification stack is visible to the user */ isStackShowing()488 private boolean isStackShowing() { 489 if (SceneContainerFlag.isEnabled()) { 490 return mPanelExpanded || mLockscreenShowing || mTrackingHeadsUp; 491 } else { 492 return mPanelExpanded; 493 } 494 } 495 496 /** 497 * Allows this notification entry to be re-ordered in the notification list temporarily until 498 * the timeout has passed. 499 * 500 * Typically this is allowed because the user has directly changed something about the 501 * notification and we are reordering based on the user's change. 502 * 503 * @param entry notification entry that can change sections even if isReorderingAllowed is false 504 * @param now current time SystemClock.elapsedRealtime 505 */ temporarilyAllowSectionChanges(@onNull NotificationEntry entry, long now)506 public void temporarilyAllowSectionChanges(@NonNull NotificationEntry entry, long now) { 507 final String entryKey = entry.getKey(); 508 final boolean wasSectionChangeAllowed = 509 mNotifStabilityManager.isSectionChangeAllowed(entry); 510 511 // If it exists, cancel previous timeout 512 if (mEntriesThatCanChangeSection.containsKey(entryKey)) { 513 mEntriesThatCanChangeSection.get(entryKey).run(); 514 } 515 516 // Schedule & store new timeout cancellable 517 mEntriesThatCanChangeSection.put( 518 entryKey, 519 mDelayableExecutor.executeAtTime( 520 () -> mEntriesThatCanChangeSection.remove(entryKey), 521 now + ALLOW_SECTION_CHANGE_TIMEOUT)); 522 523 if (!wasSectionChangeAllowed) { 524 mNotifStabilityManager.invalidateList("temporarilyAllowSectionChanges"); 525 } 526 } 527 528 final StatusBarStateController.StateListener mStatusBarStateControllerListener = 529 new StatusBarStateController.StateListener() { 530 @Override 531 public void onPulsingChanged(boolean pulsing) { 532 mPulsing = pulsing; 533 updateAllowedStates("pulsing", pulsing); 534 } 535 536 @Override 537 public void onExpandedChanged(boolean expanded) { 538 mPanelExpanded = expanded; 539 updateAllowedStates("panelExpanded", expanded); 540 } 541 542 @Override 543 public void onDozeAmountChanged(float linear, float eased) { 544 final boolean fullyDozed = linear == 1f; 545 mFullyDozed = fullyDozed; 546 updateAllowedStates("fullyDozed", fullyDozed); 547 } 548 }; 549 final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { 550 @Override 551 public void onFinishedGoingToSleep() { 552 // NOTE: this method is called much earlier than what we consider "finished" going to 553 // sleep (the animation isn't done), so we also need to check the doze amount is not 1 554 // and use the combo to determine that the locked shade is not visible. 555 mSleepy = true; 556 updateAllowedStates("sleepy", true); 557 } 558 559 @Override 560 public void onStartedWakingUp() { 561 mSleepy = false; 562 updateAllowedStates("sleepy", false); 563 } 564 }; 565 566 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)567 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 568 pw.println("pipelineRunAllowed: " + mPipelineRunAllowed); 569 pw.println(" notifPanelCollapsing: " + mNotifPanelCollapsing); 570 pw.println(" launchingNotifActivity: " + mNotifPanelLaunchingActivity); 571 if (mCheckLockScreenTransitionEnabled) { 572 pw.println(" lockscreenInGoneTransition: " + mLockscreenInGoneTransition); 573 } 574 pw.println("reorderingAllowed: " + mReorderingAllowed); 575 pw.println(" sleepy: " + mSleepy); 576 pw.println(" fullyDozed: " + mFullyDozed); 577 pw.println(" panelExpanded: " + mPanelExpanded); 578 pw.println(" pulsing: " + mPulsing); 579 pw.println(" communalShowing: " + mCommunalShowing); 580 pw.println("isSuppressingPipelineRun: " + mIsSuppressingPipelineRun); 581 pw.println("isSuppressingGroupChange: " + mIsSuppressingGroupChange); 582 pw.println("isSuppressingEntryReorder: " + mIsSuppressingEntryReorder); 583 if (StabilizeHeadsUpGroup.isEnabled()) { 584 pw.println("headsUpGroupKeys: " + mHeadsUpGroupKeys.size()); 585 } 586 pw.println("entriesWithSuppressedSectionChange: " 587 + mEntriesWithSuppressedSectionChange.size()); 588 for (String key : mEntriesWithSuppressedSectionChange) { 589 pw.println(" " + key); 590 } 591 pw.println("entriesThatCanChangeSection: " + mEntriesThatCanChangeSection.size()); 592 for (String key : mEntriesThatCanChangeSection.keySet()) { 593 pw.println(" " + key); 594 } 595 } 596 onShadeOrQsClosingChanged(boolean isClosing)597 private void onShadeOrQsClosingChanged(boolean isClosing) { 598 mNotifPanelCollapsing = isClosing; 599 updateAllowedStates("notifPanelCollapsing", isClosing); 600 } 601 onLaunchingActivityChanged(boolean isLaunchingActivity)602 private void onLaunchingActivityChanged(boolean isLaunchingActivity) { 603 mNotifPanelLaunchingActivity = isLaunchingActivity; 604 updateAllowedStates("notifPanelLaunchingActivity", isLaunchingActivity); 605 } 606 onCommunalShowingChanged(boolean isShowing)607 private void onCommunalShowingChanged(boolean isShowing) { 608 mCommunalShowing = isShowing; 609 updateAllowedStates("communalShowing", isShowing); 610 } 611 onLockscreenKeyguardStateTransitionValueChanged(float value)612 private void onLockscreenKeyguardStateTransitionValueChanged(float value) { 613 if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { 614 return; 615 } 616 617 final boolean isShowing = value > 0.0f; 618 if (isShowing == mLockscreenShowing) { 619 return; 620 } 621 622 mLockscreenShowing = isShowing; 623 updateAllowedStates("lockscreenShowing", isShowing); 624 } 625 onTrackingHeadsUpModeChanged(boolean isTrackingHeadsUp)626 private void onTrackingHeadsUpModeChanged(boolean isTrackingHeadsUp) { 627 mTrackingHeadsUp = isTrackingHeadsUp; 628 updateAllowedStates("trackingHeadsUp", isTrackingHeadsUp); 629 } 630 onLockscreenInGoneTransitionChanged(boolean inGoneTransition)631 private void onLockscreenInGoneTransitionChanged(boolean inGoneTransition) { 632 if (!mCheckLockScreenTransitionEnabled) { 633 return; 634 } 635 if (inGoneTransition == mLockscreenInGoneTransition) { 636 return; 637 } 638 mLockscreenInGoneTransition = inGoneTransition; 639 updateAllowedStates("lockscreenInGoneTransition", mLockscreenInGoneTransition); 640 } 641 } 642