• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.phone;
18 
19 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
20 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
21 
22 import android.annotation.NonNull;
23 import android.graphics.Point;
24 import android.os.Bundle;
25 import android.os.PowerManager;
26 import android.os.SystemClock;
27 import android.os.SystemProperties;
28 import android.util.Log;
29 import android.view.MotionEvent;
30 import android.view.View;
31 
32 import androidx.annotation.MainThread;
33 import androidx.annotation.Nullable;
34 
35 import com.android.app.tracing.TraceUtils;
36 import com.android.internal.annotations.VisibleForTesting;
37 import com.android.keyguard.KeyguardUpdateMonitor;
38 import com.android.systemui.assist.AssistManager;
39 import com.android.systemui.biometrics.AuthController;
40 import com.android.systemui.dagger.SysUISingleton;
41 import com.android.systemui.doze.DozeHost;
42 import com.android.systemui.doze.DozeLog;
43 import com.android.systemui.doze.DozeReceiver;
44 import com.android.systemui.keyguard.WakefulnessLifecycle;
45 import com.android.systemui.keyguard.domain.interactor.DozeInteractor;
46 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
47 import com.android.systemui.shade.NotificationShadeWindowViewController;
48 import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
49 import com.android.systemui.statusbar.NotificationShadeWindowController;
50 import com.android.systemui.statusbar.PulseExpansionHandler;
51 import com.android.systemui.statusbar.StatusBarState;
52 import com.android.systemui.statusbar.SysuiStatusBarStateController;
53 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
54 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
55 import com.android.systemui.statusbar.policy.BatteryController;
56 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
57 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
58 import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
59 import com.android.systemui.util.Assert;
60 import com.android.systemui.util.CopyOnLoopListenerSet;
61 import com.android.systemui.util.IListenerSet;
62 
63 import dagger.Lazy;
64 
65 import kotlin.Unit;
66 
67 import javax.inject.Inject;
68 
69 /**
70  * Implementation of DozeHost for SystemUI.
71  */
72 @SysUISingleton
73 public final class DozeServiceHost implements DozeHost {
74     private static final String TAG = "DozeServiceHost";
75     private final IListenerSet<Callback> mCallbacks = new CopyOnLoopListenerSet<>();
76     private final DozeLog mDozeLog;
77     private final PowerManager mPowerManager;
78     private boolean mAnimateWakeup;
79     private boolean mIgnoreTouchWhilePulsing;
80     private final HasPendingScreenOffCallbackChangeListener
81             mDefaultHasPendingScreenOffCallbackChangeListener =
82                     hasPendingScreenOffCallback -> { /* no op */ };
83     private HasPendingScreenOffCallbackChangeListener mHasPendingScreenOffCallbackChangeListener =
84             mDefaultHasPendingScreenOffCallbackChangeListener;
85     private Runnable mPendingScreenOffCallback;
86     @VisibleForTesting
87     boolean mWakeLockScreenPerformsAuth = SystemProperties.getBoolean(
88             "persist.sysui.wake_performs_auth", true);
89     private boolean mDozingRequested;
90     private boolean mPulsing;
91     private final WakefulnessLifecycle mWakefulnessLifecycle;
92     private final SysuiStatusBarStateController mStatusBarStateController;
93     private final DeviceProvisionedController mDeviceProvisionedController;
94     private final HeadsUpManager mHeadsUpManager;
95     private final BatteryController mBatteryController;
96     private final ScrimController mScrimController;
97     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
98     private final Lazy<AssistManager> mAssistManagerLazy;
99     private final DozeScrimController mDozeScrimController;
100     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
101     private final PulseExpansionHandler mPulseExpansionHandler;
102     private final NotificationShadeWindowController mNotificationShadeWindowController;
103     private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
104     private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
105     private final AuthController mAuthController;
106     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
107     private final ShadeLockscreenInteractor mShadeLockscreenInteractor;
108     private View mAmbientIndicationContainer;
109     private CentralSurfaces mCentralSurfaces;
110     private boolean mAlwaysOnSuppressed;
111     private boolean mPulsePending;
112     private final DozeInteractor mDozeInteractor;
113 
114     @Inject
DozeServiceHost(DozeLog dozeLog, PowerManager powerManager, WakefulnessLifecycle wakefulnessLifecycle, SysuiStatusBarStateController statusBarStateController, DeviceProvisionedController deviceProvisionedController, HeadsUpManager headsUpManager, BatteryController batteryController, ScrimController scrimController, Lazy<BiometricUnlockController> biometricUnlockControllerLazy, Lazy<AssistManager> assistManagerLazy, DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor, PulseExpansionHandler pulseExpansionHandler, NotificationShadeWindowController notificationShadeWindowController, NotificationWakeUpCoordinator notificationWakeUpCoordinator, AuthController authController, ShadeLockscreenInteractor shadeLockscreenInteractor, DozeInteractor dozeInteractor)115     public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager,
116             WakefulnessLifecycle wakefulnessLifecycle,
117             SysuiStatusBarStateController statusBarStateController,
118             DeviceProvisionedController deviceProvisionedController,
119             HeadsUpManager headsUpManager, BatteryController batteryController,
120             ScrimController scrimController,
121             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
122             Lazy<AssistManager> assistManagerLazy,
123             DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
124             PulseExpansionHandler pulseExpansionHandler,
125             NotificationShadeWindowController notificationShadeWindowController,
126             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
127             AuthController authController,
128             ShadeLockscreenInteractor shadeLockscreenInteractor,
129             DozeInteractor dozeInteractor) {
130         super();
131         mDozeLog = dozeLog;
132         mPowerManager = powerManager;
133         mWakefulnessLifecycle = wakefulnessLifecycle;
134         mStatusBarStateController = statusBarStateController;
135         mDeviceProvisionedController = deviceProvisionedController;
136         mHeadsUpManager = headsUpManager;
137         mBatteryController = batteryController;
138         mScrimController = scrimController;
139         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
140         mAssistManagerLazy = assistManagerLazy;
141         mDozeScrimController = dozeScrimController;
142         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
143         mPulseExpansionHandler = pulseExpansionHandler;
144         mNotificationShadeWindowController = notificationShadeWindowController;
145         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
146         mAuthController = authController;
147         mShadeLockscreenInteractor = shadeLockscreenInteractor;
148         mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
149         mDozeInteractor = dozeInteractor;
150     }
151 
152     // TODO: we should try to not pass status bar in here if we can avoid it.
153 
154     /**
155      * Initialize instance with objects only available later during execution.
156      */
initialize( CentralSurfaces centralSurfaces, StatusBarKeyguardViewManager statusBarKeyguardViewManager, NotificationShadeWindowViewController notificationShadeWindowViewController, View ambientIndicationContainer)157     public void initialize(
158             CentralSurfaces centralSurfaces,
159             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
160             NotificationShadeWindowViewController notificationShadeWindowViewController,
161             View ambientIndicationContainer) {
162         mCentralSurfaces = centralSurfaces;
163         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
164         mNotificationShadeWindowViewController = notificationShadeWindowViewController;
165         mAmbientIndicationContainer = ambientIndicationContainer;
166     }
167 
168 
169     @Override
toString()170     public String toString() {
171         return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
172     }
173 
firePowerSaveChanged(boolean active)174     void firePowerSaveChanged(boolean active) {
175         Assert.isMainThread();
176         for (Callback callback : mCallbacks) {
177             callback.onPowerSaveChanged(active);
178         }
179     }
180 
181     /**
182      * Notify the registered callback about SPFS fingerprint acquisition started event.
183      */
fireSideFpsAcquisitionStarted()184     public void fireSideFpsAcquisitionStarted() {
185         Assert.isMainThread();
186         for (Callback callback : mCallbacks) {
187             callback.onSideFingerprintAcquisitionStarted();
188         }
189     }
190 
fireNotificationPulse(NotificationEntry entry)191     void fireNotificationPulse(NotificationEntry entry) {
192         Runnable pulseSuppressedListener = () -> {
193             mHeadsUpManager.removeNotification(
194                     entry.getKey(),
195                     /* releaseImmediately= */ true,
196                     /* animate= */ false,
197                     "fireNotificationPulse"
198             );
199         };
200         Assert.isMainThread();
201         for (Callback callback : mCallbacks) {
202             callback.onNotificationAlerted(pulseSuppressedListener);
203         }
204     }
205 
getDozingRequested()206     boolean getDozingRequested() {
207         return mDozingRequested;
208     }
209 
isPulsing()210     public boolean isPulsing() {
211         return mPulsing;
212     }
213 
214 
215     @Override
addCallback(@onNull Callback callback)216     public void addCallback(@NonNull Callback callback) {
217         Assert.isMainThread();
218         mCallbacks.addIfAbsent(callback);
219     }
220 
221     @Override
removeCallback(@onNull Callback callback)222     public void removeCallback(@NonNull Callback callback) {
223         Assert.isMainThread();
224         mCallbacks.remove(callback);
225     }
226 
227     @Override
startDozing()228     public void startDozing() {
229         if (!mDozingRequested) {
230             mDozingRequested = true;
231             updateDozing();
232             mDozeLog.traceDozing(mStatusBarStateController.isDozing());
233             // This is initialized in a CoreStartable, but binder calls from DreamManagerService can
234             // arrive earlier
235             if (mCentralSurfaces != null) {
236                 mCentralSurfaces.updateIsKeyguard();
237             }
238         }
239     }
240 
updateDozing()241     void updateDozing() {
242         Assert.isMainThread();
243 
244         boolean dozing;
245         if (SceneContainerFlag.isEnabled()) {
246             dozing = mDozingRequested && mDozeInteractor.canDozeFromCurrentScene();
247         } else {
248             dozing = mDozingRequested
249                     && mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
250         }
251 
252         // When in wake-and-unlock we may not have received a change to StatusBarState
253         // but we still should not be dozing, manually set to false.
254         if (mBiometricUnlockControllerLazy.get().getMode()
255                 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
256             dozing = false;
257         }
258 
259         for (Callback callback : mCallbacks) {
260             callback.onDozingChanged(dozing);
261         }
262         mDozeInteractor.setIsDozing(dozing);
263         mStatusBarStateController.setIsDozing(dozing);
264     }
265 
266     @Override
pulseWhileDozing(@onNull PulseCallback callback, int reason)267     public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
268         if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
269             mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
270                                  "com.android.systemui:LONG_PRESS");
271             mAssistManagerLazy.get().startAssist(new Bundle());
272             return;
273         }
274 
275         if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) {
276             mScrimController.setWakeLockScreenSensorActive(true);
277         }
278 
279         boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH
280                         && mWakeLockScreenPerformsAuth;
281         // Set the state to pulsing, so ScrimController will know what to do once we ask it to
282         // execute the transition. The pulse callback will then be invoked when the scrims
283         // are black, indicating that CentralSurfaces is ready to present the rest of the UI.
284         mPulsing = true;
285         mDozeScrimController.pulse(new PulseCallback() {
286             @Override
287             public void onPulseStarted() {
288                 callback.onPulseStarted(); // requestState(DozeMachine.State.DOZE_PULSING)
289                 mCentralSurfaces.updateNotificationPanelTouchState();
290                 setPulsing(true);
291             }
292 
293             @Override
294             public void onPulseFinished() {
295                 mPulsing = false;
296                 callback.onPulseFinished(); // requestState(DozeMachine.State.DOZE_PULSE_DONE)
297                 mCentralSurfaces.updateNotificationPanelTouchState();
298                 mScrimController.setWakeLockScreenSensorActive(false);
299                 setPulsing(false);
300             }
301 
302             private void setPulsing(boolean pulsing) {
303                 mStatusBarKeyguardViewManager.setPulsing(pulsing);
304                 mShadeLockscreenInteractor.setPulsing(pulsing);
305                 mStatusBarStateController.setPulsing(pulsing);
306                 mIgnoreTouchWhilePulsing = false;
307                 if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) {
308                     mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */);
309                 }
310                 mCentralSurfaces.updateScrimController();
311                 mPulseExpansionHandler.setPulsing(pulsing);
312                 mNotificationWakeUpCoordinator.setPulsing(pulsing);
313             }
314         }, reason);
315         // DozeScrimController is in pulse state, now let's ask ScrimController to start
316         // pulsing and draw the black frame, if necessary.
317         mCentralSurfaces.updateScrimController();
318     }
319 
320     @Override
stopDozing()321     public void stopDozing() {
322         if (mDozingRequested) {
323             mDozingRequested = false;
324             updateDozing();
325             mDozeLog.traceDozing(mStatusBarStateController.isDozing());
326         }
327     }
328 
329     @Override
onIgnoreTouchWhilePulsing(boolean ignore)330     public void onIgnoreTouchWhilePulsing(boolean ignore) {
331         if (ignore != mIgnoreTouchWhilePulsing) {
332             mDozeLog.tracePulseTouchDisabledByProx(ignore);
333         }
334         mIgnoreTouchWhilePulsing = ignore;
335         if (mStatusBarStateController.isDozing() && ignore) {
336             mNotificationShadeWindowViewController.cancelCurrentTouch();
337         }
338     }
339 
340     @Override
341     @MainThread
dozeTimeTick()342     public void dozeTimeTick() {
343         TraceUtils.trace("DozeServiceHost#dozeTimeTick", () -> {
344             mDozeInteractor.dozeTimeTick();
345             mAuthController.dozeTimeTick();
346             if (mAmbientIndicationContainer instanceof DozeReceiver) {
347                 ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
348             }
349             return Unit.INSTANCE;
350         });
351     }
352 
353     @Override
isPowerSaveActive()354     public boolean isPowerSaveActive() {
355         return mBatteryController.isAodPowerSave();
356     }
357 
358     @Override
isPulsingBlocked()359     public boolean isPulsingBlocked() {
360         return mBiometricUnlockControllerLazy.get().getMode()
361                 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
362     }
363 
364     @Override
isProvisioned()365     public boolean isProvisioned() {
366         return mDeviceProvisionedController.isDeviceProvisioned()
367                 && mDeviceProvisionedController.isCurrentUserSetup();
368     }
369 
370     @Override
extendPulse(int reason)371     public void extendPulse(int reason) {
372         if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) {
373             mScrimController.setWakeLockScreenSensorActive(true);
374         }
375         if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) {
376             mHeadsUpManager.extendHeadsUp();
377         } else {
378             mDozeScrimController.extendPulse();
379         }
380     }
381 
382     @Override
stopPulsing()383     public void stopPulsing() {
384         setPulsePending(false); // prevent any pending pulses from continuing
385         mDozeScrimController.pulseOutNow();
386     }
387 
388     @Override
setAnimateWakeup(boolean animateWakeup)389     public void setAnimateWakeup(boolean animateWakeup) {
390         if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
391                 || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) {
392             // Too late to change the wakeup animation.
393             return;
394         }
395         mAnimateWakeup = animateWakeup;
396     }
397 
398     @Override
onSlpiTap(float screenX, float screenY)399     public void onSlpiTap(float screenX, float screenY) {
400         if (screenX < 0 || screenY < 0) return;
401         dispatchTouchEventToAmbientIndicationContainer(screenX, screenY);
402 
403         mDozeInteractor.setLastTapToWakePosition(new Point((int) screenX, (int) screenY));
404     }
405 
dispatchTouchEventToAmbientIndicationContainer(float screenX, float screenY)406     private void dispatchTouchEventToAmbientIndicationContainer(float screenX, float screenY) {
407         if (mAmbientIndicationContainer != null
408                 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
409             int[] locationOnScreen = new int[2];
410             mAmbientIndicationContainer.getLocationOnScreen(locationOnScreen);
411             float viewX = screenX - locationOnScreen[0];
412             float viewY = screenY - locationOnScreen[1];
413             if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
414                     && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
415 
416                 // Dispatch a tap
417                 long now = SystemClock.elapsedRealtime();
418                 MotionEvent ev = MotionEvent.obtain(
419                         now, now, MotionEvent.ACTION_DOWN, screenX, screenY, 0);
420                 mAmbientIndicationContainer.dispatchTouchEvent(ev);
421                 ev.recycle();
422                 ev = MotionEvent.obtain(
423                         now, now, MotionEvent.ACTION_UP, screenX, screenY, 0);
424                 mAmbientIndicationContainer.dispatchTouchEvent(ev);
425                 ev.recycle();
426             }
427         }
428     }
429 
430     @Override
setDozeScreenBrightness(int brightness)431     public void setDozeScreenBrightness(int brightness) {
432         mNotificationShadeWindowController.setDozeScreenBrightness(brightness);
433     }
434 
435 
436     @Override
setDozeScreenBrightnessFloat(float brightness)437     public void setDozeScreenBrightnessFloat(float brightness) {
438         mNotificationShadeWindowController.setDozeScreenBrightnessFloat(brightness);
439     }
440 
441     @Override
setAodDimmingScrim(float scrimOpacity)442     public void setAodDimmingScrim(float scrimOpacity) {
443         mDozeLog.traceSetAodDimmingScrim(scrimOpacity);
444         mScrimController.setAodFrontScrimAlpha(scrimOpacity);
445     }
446 
447     @Override
prepareForGentleSleep(Runnable onDisplayOffCallback)448     public void prepareForGentleSleep(Runnable onDisplayOffCallback) {
449         if (mPendingScreenOffCallback != null) {
450             Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one.");
451         }
452         mPendingScreenOffCallback = onDisplayOffCallback;
453         mHasPendingScreenOffCallbackChangeListener.onHasPendingScreenOffCallbackChanged(true);
454         mCentralSurfaces.updateScrimController();
455     }
456 
457     @Override
cancelGentleSleep()458     public void cancelGentleSleep() {
459         mPendingScreenOffCallback = null;
460         mHasPendingScreenOffCallbackChangeListener.onHasPendingScreenOffCallbackChanged(false);
461         if (mScrimController.getState() == ScrimState.OFF) {
462             mCentralSurfaces.updateScrimController();
463         }
464     }
465 
466     /**
467      * When the dozing host is waiting for scrims to fade out to change the display state.
468      */
hasPendingScreenOffCallback()469     public boolean hasPendingScreenOffCallback() {
470         return mPendingScreenOffCallback != null;
471     }
472 
473     /**
474      * Sets a listener to be notified whenever the result of {@link #hasPendingScreenOffCallback()}
475      * changes.
476      *
477      * <p>Setting the listener automatically notifies the listener inline.
478      */
setHasPendingScreenOffCallbackChangeListener( @ullable HasPendingScreenOffCallbackChangeListener listener)479     public void setHasPendingScreenOffCallbackChangeListener(
480             @Nullable HasPendingScreenOffCallbackChangeListener listener) {
481         mHasPendingScreenOffCallbackChangeListener = listener != null
482                 ? listener
483                 : mDefaultHasPendingScreenOffCallbackChangeListener;
484 
485         mHasPendingScreenOffCallbackChangeListener.onHasPendingScreenOffCallbackChanged(
486                 mPendingScreenOffCallback != null);
487     }
488 
489     /**
490      * Executes an nullifies the pending display state callback.
491      *
492      * @see #hasPendingScreenOffCallback()
493      * @see #prepareForGentleSleep(Runnable)
494      */
executePendingScreenOffCallback()495     void executePendingScreenOffCallback() {
496         if (mPendingScreenOffCallback == null) {
497             return;
498         }
499         mPendingScreenOffCallback.run();
500         mPendingScreenOffCallback = null;
501         mHasPendingScreenOffCallbackChangeListener.onHasPendingScreenOffCallbackChanged(false);
502     }
503 
shouldAnimateWakeup()504     boolean shouldAnimateWakeup() {
505         return mAnimateWakeup;
506     }
507 
getIgnoreTouchWhilePulsing()508     boolean getIgnoreTouchWhilePulsing() {
509         return mIgnoreTouchWhilePulsing;
510     }
511 
512     /**
513      * Suppresses always-on-display and waking up the display for notifications.
514      * Does not disable wakeup gestures like pickup and tap.
515      */
setAlwaysOnSuppressed(boolean suppressed)516     void setAlwaysOnSuppressed(boolean suppressed) {
517         if (suppressed == mAlwaysOnSuppressed) {
518             return;
519         }
520         mAlwaysOnSuppressed = suppressed;
521         Assert.isMainThread();
522         for (Callback callback : mCallbacks) {
523             callback.onAlwaysOnSuppressedChanged(suppressed);
524         }
525     }
526 
527     @Override
isPulsePending()528     public boolean isPulsePending() {
529         return mPulsePending;
530     }
531 
532     @Override
setPulsePending(boolean isPulsePending)533     public void setPulsePending(boolean isPulsePending) {
534         mPulsePending = isPulsePending;
535     }
536 
537     /**
538      * Whether always-on-display is being suppressed. This does not affect wakeup gestures like
539      * pickup and tap.
540      */
isAlwaysOnSuppressed()541     public boolean isAlwaysOnSuppressed() {
542         return mAlwaysOnSuppressed;
543     }
544 
545     final OnHeadsUpChangedListener mOnHeadsUpChangedListener = new OnHeadsUpChangedListener() {
546         @Override
547         public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
548             if (mStatusBarStateController.isDozing() && isHeadsUp) {
549                 entry.setPulseSuppressed(false);
550                 fireNotificationPulse(entry);
551                 if (isPulsing()) {
552                     mDozeScrimController.cancelPendingPulseTimeout();
553                 }
554             }
555             if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
556                 // There are no longer any notifications to show.  We should end the
557                 // pulse now.
558                 stopPulsing();
559             }
560         }
561     };
562 
563     /**
564      * Defines interface for classes that can be notified about changes to having or not having a
565      * pending screen-off callback.
566      */
567     public interface HasPendingScreenOffCallbackChangeListener {
568 
569         /** Notifies that there now is or isn't a pending screen-off callback. */
onHasPendingScreenOffCallbackChanged(boolean hasPendingScreenOffCallback)570         void onHasPendingScreenOffCallbackChanged(boolean hasPendingScreenOffCallback);
571     }
572 }
573