diff options
10 files changed, 760 insertions, 429 deletions
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 9d3362ee8c65..aebb62d7b069 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -32,6 +32,7 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.PowerManager; import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; @@ -107,6 +108,8 @@ import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.DozeScrimController; +import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LightBarController; @@ -295,6 +298,9 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt ScrimController scrimController, Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, Lazy<BiometricUnlockController> biometricUnlockControllerLazy, + DozeServiceHost dozeServiceHost, + PowerManager powerManager, + DozeScrimController dozeScrimController, /* Car Settings injected components. */ CarNavigationBarController carNavigationBarController) { @@ -358,7 +364,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt dozeParameters, scrimController, lockscreenWallpaperLazy, - biometricUnlockControllerLazy); + biometricUnlockControllerLazy, + dozeServiceHost, + powerManager, + dozeScrimController); mScrimController = scrimController; mCarNavigationBarController = carNavigationBarController; } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java index 6674c12ab613..9032c6fc8639 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java @@ -20,6 +20,7 @@ import com.android.systemui.ActivityStarterDelegate; import com.android.systemui.appops.AppOpsController; import com.android.systemui.appops.AppOpsControllerImpl; import com.android.systemui.classifier.FalsingManagerProxy; +import com.android.systemui.doze.DozeHost; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.FalsingManager; @@ -33,6 +34,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl; +import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -241,5 +243,10 @@ public abstract class DependencyBinder { /** */ @Binds - public abstract FalsingManager provideFalsingmanager(FalsingManagerProxy falsingManagerImpl); + public abstract FalsingManager provideFalsingManager(FalsingManagerProxy falsingManagerImpl); + + /** + */ + @Binds + public abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 033171a28c62..1e8e28fd1614 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -55,10 +55,10 @@ import javax.inject.Singleton; @Singleton public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { - private static final String TAG = "BiometricUnlockController"; + private static final String TAG = "BiometricUnlockCtrl"; private static final boolean DEBUG_BIO_WAKELOCK = KeyguardConstants.DEBUG_BIOMETRIC_WAKELOCK; private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000; - private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock"; + private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock"; @IntDef(prefix = { "MODE_" }, value = { MODE_NONE, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 50d33a70fed5..bc482353753d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -24,7 +24,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.MathUtils; -import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.MainResources; import com.android.systemui.doze.AlwaysOnDisplayPolicy; @@ -188,12 +187,7 @@ public class DozeParameters implements TunerService.Tunable, return; } mControlScreenOffAnimation = controlScreenOffAnimation; - getPowerManager().setDozeAfterScreenOff(!controlScreenOffAnimation); - } - - @VisibleForTesting - protected PowerManager getPowerManager() { - return mPowerManager; + mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation); } private boolean getBoolean(String propName, int resId) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index fe3c04e3cda3..1ecc4899d5e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -29,10 +29,12 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import javax.inject.Inject; +import javax.inject.Singleton; /** * Controller which handles all the doze animations of the scrims. */ +@Singleton public class DozeScrimController implements StateListener { private static final String TAG = "DozeScrimController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java new file mode 100644 index 000000000000..28543555bf4d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; +import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; + +import android.annotation.NonNull; +import android.os.Bundle; +import android.os.PowerManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.doze.DozeEvent; +import com.android.systemui.doze.DozeHost; +import com.android.systemui.doze.DozeLog; +import com.android.systemui.doze.DozeReceiver; +import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; + +import java.util.ArrayList; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import dagger.Lazy; + +/** + * Implementation of DozeHost for SystemUI. + */ +@Singleton +public final class DozeServiceHost implements DozeHost { + private static final String TAG = "DozeServiceHost"; + private final ArrayList<Callback> mCallbacks = new ArrayList<>(); + private final DozeLog mDozeLog; + private final PowerManager mPowerManager; + private boolean mAnimateWakeup; + private boolean mAnimateScreenOff; + private boolean mIgnoreTouchWhilePulsing; + private Runnable mPendingScreenOffCallback; + @VisibleForTesting + boolean mWakeLockScreenPerformsAuth = SystemProperties.getBoolean( + "persist.sysui.wake_performs_auth", true); + private boolean mDozingRequested; + private boolean mDozing; + private boolean mPulsing; + private WakefulnessLifecycle mWakefulnessLifecycle; + private final SysuiStatusBarStateController mStatusBarStateController; + private final DeviceProvisionedController mDeviceProvisionedController; + private final HeadsUpManagerPhone mHeadsUpManagerPhone; + private final BatteryController mBatteryController; + private final ScrimController mScrimController; + private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; + private BiometricUnlockController mBiometricUnlockController; + private final KeyguardViewMediator mKeyguardViewMediator; + private final AssistManager mAssistManager; + private final DozeScrimController mDozeScrimController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final VisualStabilityManager mVisualStabilityManager; + private final PulseExpansionHandler mPulseExpansionHandler; + private final StatusBarWindowController mStatusBarWindowController; + private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; + private NotificationIconAreaController mNotificationIconAreaController; + private StatusBarWindowViewController mStatusBarWindowViewController; + private StatusBarWindowView mStatusBarWindow; + private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private NotificationPanelView mNotificationPanel; + private View mAmbientIndicationContainer; + private StatusBar mStatusBar; + + @Inject + public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + DeviceProvisionedController deviceProvisionedController, + HeadsUpManagerPhone headsUpManagerPhone, BatteryController batteryController, + ScrimController scrimController, + Lazy<BiometricUnlockController> biometricUnlockControllerLazy, + KeyguardViewMediator keyguardViewMediator, + AssistManager assistManager, + DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor, + VisualStabilityManager visualStabilityManager, + PulseExpansionHandler pulseExpansionHandler, + StatusBarWindowController statusBarWindowController, + NotificationWakeUpCoordinator notificationWakeUpCoordinator) { + super(); + mDozeLog = dozeLog; + mPowerManager = powerManager; + mWakefulnessLifecycle = wakefulnessLifecycle; + mStatusBarStateController = statusBarStateController; + mDeviceProvisionedController = deviceProvisionedController; + mHeadsUpManagerPhone = headsUpManagerPhone; + mBatteryController = batteryController; + mScrimController = scrimController; + mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; + mKeyguardViewMediator = keyguardViewMediator; + mAssistManager = assistManager; + mDozeScrimController = dozeScrimController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mVisualStabilityManager = visualStabilityManager; + mPulseExpansionHandler = pulseExpansionHandler; + mStatusBarWindowController = statusBarWindowController; + mNotificationWakeUpCoordinator = notificationWakeUpCoordinator; + } + + // TODO: we should try to not pass status bar in here if we can avoid it. + + /** + * Initialize instance with objects only available later during execution. + */ + public void initialize(StatusBar statusBar, + NotificationIconAreaController notificationIconAreaController, + StatusBarWindowViewController statusBarWindowViewController, + StatusBarWindowView statusBarWindow, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, + NotificationPanelView notificationPanel, View ambientIndicationContainer) { + mStatusBar = statusBar; + mNotificationIconAreaController = notificationIconAreaController; + mStatusBarWindowViewController = statusBarWindowViewController; + mStatusBarWindow = statusBarWindow; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; + mNotificationPanel = notificationPanel; + mAmbientIndicationContainer = ambientIndicationContainer; + mBiometricUnlockController = mBiometricUnlockControllerLazy.get(); + } + + @Override + public String toString() { + return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]"; + } + + void firePowerSaveChanged(boolean active) { + for (Callback callback : mCallbacks) { + callback.onPowerSaveChanged(active); + } + } + + void fireNotificationPulse(NotificationEntry entry) { + Runnable pulseSuppressedListener = () -> { + entry.setPulseSuppressed(true); + mNotificationIconAreaController.updateAodNotificationIcons(); + }; + for (Callback callback : mCallbacks) { + callback.onNotificationAlerted(pulseSuppressedListener); + } + } + + boolean getDozingRequested() { + return mDozingRequested; + } + + boolean isPulsing() { + return mPulsing; + } + + + @Override + public void addCallback(@NonNull Callback callback) { + mCallbacks.add(callback); + } + + @Override + public void removeCallback(@NonNull Callback callback) { + mCallbacks.remove(callback); + } + + @Override + public void startDozing() { + if (!mDozingRequested) { + mDozingRequested = true; + mDozeLog.traceDozing(mDozing); + updateDozing(); + mStatusBar.updateIsKeyguard(); + } + } + + void updateDozing() { + // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked. + boolean + dozing = + mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD + || mBiometricUnlockController.getMode() + == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; + // When in wake-and-unlock we may not have received a change to StatusBarState + // but we still should not be dozing, manually set to false. + if (mBiometricUnlockController.getMode() + == BiometricUnlockController.MODE_WAKE_AND_UNLOCK) { + dozing = false; + } + + + mStatusBarStateController.setIsDozing(dozing); + } + + @Override + public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { + if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) { + mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, + "com.android.systemui:LONG_PRESS"); + mAssistManager.startAssist(new Bundle()); + return; + } + + if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + mScrimController.setWakeLockScreenSensorActive(true); + } + + if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) { + mStatusBarWindowViewController.suppressWakeUpGesture(true); + } + + boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + && mWakeLockScreenPerformsAuth; + // Set the state to pulsing, so ScrimController will know what to do once we ask it to + // execute the transition. The pulse callback will then be invoked when the scrims + // are black, indicating that StatusBar is ready to present the rest of the UI. + mPulsing = true; + mDozeScrimController.pulse(new PulseCallback() { + @Override + public void onPulseStarted() { + callback.onPulseStarted(); + mStatusBar.updateNotificationPanelTouchState(); + setPulsing(true); + } + + @Override + public void onPulseFinished() { + mPulsing = false; + callback.onPulseFinished(); + mStatusBar.updateNotificationPanelTouchState(); + mScrimController.setWakeLockScreenSensorActive(false); + if (mStatusBarWindow != null) { + mStatusBarWindowViewController.suppressWakeUpGesture(false); + } + setPulsing(false); + } + + private void setPulsing(boolean pulsing) { + mStatusBarStateController.setPulsing(pulsing); + mStatusBarKeyguardViewManager.setPulsing(pulsing); + mKeyguardViewMediator.setPulsing(pulsing); + mNotificationPanel.setPulsing(pulsing); + mVisualStabilityManager.setPulsing(pulsing); + mStatusBarWindowViewController.setPulsing(pulsing); + mIgnoreTouchWhilePulsing = false; + if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) { + mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */); + } + mStatusBar.updateScrimController(); + mPulseExpansionHandler.setPulsing(pulsing); + mNotificationWakeUpCoordinator.setPulsing(pulsing); + } + }, reason); + // DozeScrimController is in pulse state, now let's ask ScrimController to start + // pulsing and draw the black frame, if necessary. + mStatusBar.updateScrimController(); + } + + @Override + public void stopDozing() { + if (mDozingRequested) { + mDozingRequested = false; + mDozeLog.traceDozing(mDozing); + updateDozing(); + } + } + + @Override + public void onIgnoreTouchWhilePulsing(boolean ignore) { + if (ignore != mIgnoreTouchWhilePulsing) { + mDozeLog.tracePulseTouchDisabledByProx(ignore); + } + mIgnoreTouchWhilePulsing = ignore; + if (mDozing && ignore) { + mStatusBarWindowViewController.cancelCurrentTouch(); + } + } + + @Override + public void dozeTimeTick() { + mNotificationPanel.dozeTimeTick(); + if (mAmbientIndicationContainer instanceof DozeReceiver) { + ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick(); + } + } + + @Override + public boolean isPowerSaveActive() { + return mBatteryController.isAodPowerSave(); + } + + @Override + public boolean isPulsingBlocked() { + return mBiometricUnlockController.getMode() + == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; + } + + @Override + public boolean isProvisioned() { + return mDeviceProvisionedController.isDeviceProvisioned() + && mDeviceProvisionedController.isCurrentUserSetup(); + } + + @Override + public boolean isBlockingDoze() { + if (mBiometricUnlockController.hasPendingAuthentication()) { + Log.i(StatusBar.TAG, "Blocking AOD because fingerprint has authenticated"); + return true; + } + return false; + } + + @Override + public void extendPulse(int reason) { + if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + mScrimController.setWakeLockScreenSensorActive(true); + } + if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) { + mHeadsUpManagerPhone.extendHeadsUp(); + } else { + mDozeScrimController.extendPulse(); + } + } + + @Override + public void stopPulsing() { + if (mDozeScrimController.isPulsing()) { + mDozeScrimController.pulseOutNow(); + } + } + + @Override + public void setAnimateWakeup(boolean animateWakeup) { + if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE + || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) { + // Too late to change the wakeup animation. + return; + } + mAnimateWakeup = animateWakeup; + } + + @Override + public void setAnimateScreenOff(boolean animateScreenOff) { + mAnimateScreenOff = animateScreenOff; + } + + @Override + public void onSlpiTap(float screenX, float screenY) { + if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null + && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) { + int[] locationOnScreen = new int[2]; + mAmbientIndicationContainer.getLocationOnScreen(locationOnScreen); + float viewX = screenX - locationOnScreen[0]; + float viewY = screenY - locationOnScreen[1]; + if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth() + && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) { + + // Dispatch a tap + long now = SystemClock.elapsedRealtime(); + MotionEvent ev = MotionEvent.obtain( + now, now, MotionEvent.ACTION_DOWN, screenX, screenY, 0); + mAmbientIndicationContainer.dispatchTouchEvent(ev); + ev.recycle(); + ev = MotionEvent.obtain( + now, now, MotionEvent.ACTION_UP, screenX, screenY, 0); + mAmbientIndicationContainer.dispatchTouchEvent(ev); + ev.recycle(); + } + } + } + + @Override + public void setDozeScreenBrightness(int value) { + mStatusBarWindowController.setDozeScreenBrightness(value); + } + + @Override + public void setAodDimmingScrim(float scrimOpacity) { + mScrimController.setAodFrontScrimAlpha(scrimOpacity); + } + + + + @Override + public void prepareForGentleSleep(Runnable onDisplayOffCallback) { + if (mPendingScreenOffCallback != null) { + Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one."); + } + mPendingScreenOffCallback = onDisplayOffCallback; + mStatusBar.updateScrimController(); + } + + @Override + public void cancelGentleSleep() { + mPendingScreenOffCallback = null; + if (mScrimController.getState() == ScrimState.OFF) { + mStatusBar.updateScrimController(); + } + } + + /** + * When the dozing host is waiting for scrims to fade out to change the display state. + */ + boolean hasPendingScreenOffCallback() { + return mPendingScreenOffCallback != null; + } + + /** + * Executes an nullifies the pending display state callback. + * + * @see #hasPendingScreenOffCallback() + * @see #prepareForGentleSleep(Runnable) + */ + void executePendingScreenOffCallback() { + if (mPendingScreenOffCallback == null) { + return; + } + mPendingScreenOffCallback.run(); + mPendingScreenOffCallback = null; + } + + boolean shouldAnimateWakeup() { + return mAnimateWakeup; + } + + boolean shouldAnimateScreenOff() { + return mAnimateScreenOff; + } + + public void setDozing(boolean dozing) { + mDozing = dozing; + } + + boolean getIgnoreTouchWhilePulsing() { + return mIgnoreTouchWhilePulsing; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 6064fbedf63d..35039a0d74f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -60,11 +60,13 @@ import java.lang.annotation.RetentionPolicy; import java.util.function.Consumer; import javax.inject.Inject; +import javax.inject.Singleton; /** * Controls both the scrim behind the notifications and in front of the notifications (when a * security method gets shown). */ +@Singleton public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener, Dumpable { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 2e0fbfa6ea0b..971843ec0187 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -50,7 +50,6 @@ import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -157,10 +156,8 @@ import com.android.systemui.bubbles.BubbleController; import com.android.systemui.charging.WirelessChargingAnimation; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; -import com.android.systemui.doze.DozeReceiver; import com.android.systemui.fragments.ExtensionFragmentListener; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.KeyguardSliceProvider; @@ -347,7 +344,7 @@ public class StatusBar extends SystemUI implements DemoMode, /** * The {@link StatusBarState} of the status bar. */ - protected int mState; + protected int mState; // TODO: remove this. Just use StatusBarStateController protected boolean mBouncerShowing; private PhoneStatusBarPolicy mIconPolicy; @@ -373,7 +370,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarWindowController mStatusBarWindowController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting - DozeServiceHost mDozeServiceHost = new DozeServiceHost(); + DozeServiceHost mDozeServiceHost; private boolean mWakeUpComingFromTouch; private PointF mWakeUpTouchLocation; @@ -493,7 +490,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final UiOffloadThread mUiOffloadThread; protected boolean mDozing; - private boolean mDozingRequested; private final NotificationMediaManager mMediaManager; private final NotificationLockscreenUserManager mLockscreenUserManager; @@ -612,7 +608,6 @@ public class StatusBar extends SystemUI implements DemoMode, private ActivityLaunchAnimator mActivityLaunchAnimator; protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; - private boolean mPulsing; private final BubbleController mBubbleController; private final BubbleController.BubbleExpandListener mBubbleExpandListener; @@ -692,7 +687,10 @@ public class StatusBar extends SystemUI implements DemoMode, DozeParameters dozeParameters, ScrimController scrimController, Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, - Lazy<BiometricUnlockController> biometricUnlockControllerLazy) { + Lazy<BiometricUnlockController> biometricUnlockControllerLazy, + DozeServiceHost dozeServiceHost, + PowerManager powerManager, + DozeScrimController dozeScrimController) { super(context); mFeatureFlags = featureFlags; mLightBarController = lightBarController; @@ -749,9 +747,12 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarWindowController = statusBarWindowController; mStatusBarWindowViewControllerBuilder = statusBarWindowViewControllerBuilder; mNotifLog = notifLog; + mDozeServiceHost = dozeServiceHost; + mPowerManager = powerManager; mDozeParameters = dozeParameters; mScrimController = scrimController; mLockscreenWallpaperLazy = lockscreenWallpaperLazy; + mDozeScrimController = dozeScrimController; mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; mBubbleExpandListener = @@ -804,7 +805,6 @@ public class StatusBar extends SystemUI implements DemoMode, mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); - mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); @@ -904,6 +904,9 @@ public class StatusBar extends SystemUI implements DemoMode, startKeyguard(); mKeyguardUpdateMonitor.registerCallback(mUpdateCallback); + mDozeServiceHost.initialize(this, mNotificationIconAreaController, + mStatusBarWindowViewController, mStatusBarWindow, mStatusBarKeyguardViewManager, + mNotificationPanel, mAmbientIndicationContainer); putComponent(DozeHost.class, mDozeServiceHost); mScreenPinningRequest = new ScreenPinningRequest(mContext); @@ -1068,7 +1071,6 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf, mHeadsUpManager, mNotificationIconAreaController, mScrimController); - mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog); BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop); mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front), @@ -1729,7 +1731,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (isDozing() && isHeadsUp) { entry.setPulseSuppressed(false); mDozeServiceHost.fireNotificationPulse(entry); - if (mPulsing) { + if (mDozeServiceHost.isPulsing()) { mDozeScrimController.cancelPendingPulseTimeout(); } } @@ -1761,7 +1763,7 @@ public class StatusBar extends SystemUI implements DemoMode, } public boolean isPulsing() { - return mPulsing; + return mDozeServiceHost.isPulsing(); } public boolean hideStatusBarIconsWhenExpanded() { @@ -2824,7 +2826,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP && mKeyguardStateController.canDismissLockScreen() && !mStatusBarStateController.leaveOpenOnKeyguardHide() - && isPulsing()) { + && mDozeServiceHost.isPulsing()) { // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a pulse. // TODO: Factor this transition out of BiometricUnlockController. mBiometricUnlockController.startWakeAndUnlock( @@ -3155,7 +3157,7 @@ public class StatusBar extends SystemUI implements DemoMode, return mState == StatusBarState.FULLSCREEN_USER_SWITCHER; } - private boolean updateIsKeyguard() { + boolean updateIsKeyguard() { boolean wakeAndUnlocking = mBiometricUnlockController.getMode() == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; @@ -3163,8 +3165,8 @@ public class StatusBar extends SystemUI implements DemoMode, // there's no surface we can show to the user. Note that the device goes fully interactive // late in the transition, so we also allow the device to start dozing once the screen has // turned off fully. - boolean keyguardForDozing = mDozingRequested && - (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard)); + boolean keyguardForDozing = mDozeServiceHost.getDozingRequested() + && (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard)); boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested() || keyguardForDozing) && !wakeAndUnlocking; if (keyguardForDozing) { @@ -3580,7 +3582,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void onStateChanged(int newState) { mState = newState; updateReportRejectedTouchVisibility(); - updateDozing(); + mDozeServiceHost.updateDozing(); updateTheme(); mNavigationBarController.touchAutoDim(mDisplayId); Trace.beginSection("StatusBar#updateKeyguardState"); @@ -3618,9 +3620,11 @@ public class StatusBar extends SystemUI implements DemoMode, public void onDozingChanged(boolean isDozing) { Trace.beginSection("StatusBar#updateDozing"); mDozing = isDozing; + mDozeServiceHost.setDozing(mDozing); // Collapse the notification panel if open - boolean dozingAnimated = mDozingRequested && mDozeParameters.shouldControlScreenOff(); + boolean dozingAnimated = mDozeServiceHost.getDozingRequested() + && mDozeParameters.shouldControlScreenOff(); mNotificationPanel.resetViews(dozingAnimated); updateQsExpansionEnabled(); @@ -3628,26 +3632,12 @@ public class StatusBar extends SystemUI implements DemoMode, mEntryManager.updateNotifications("onDozingChanged"); updateDozingState(); + mDozeServiceHost.updateDozing(); updateScrimController(); updateReportRejectedTouchVisibility(); Trace.endSection(); } - private void updateDozing() { - // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked. - boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD - || mBiometricUnlockController.getMode() - == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; - // When in wake-and-unlock we may not have received a change to mState - // but we still should not be dozing, manually set to false. - if (mBiometricUnlockController.getMode() == - BiometricUnlockController.MODE_WAKE_AND_UNLOCK) { - dozing = false; - } - - mStatusBarStateController.setIsDozing(dozing); - } - private void updateKeyguardState() { mKeyguardStateController.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), mStatusBarKeyguardViewManager.isOccluded()); @@ -3872,10 +3862,11 @@ public class StatusBar extends SystemUI implements DemoMode, * collapse the panel after we expanded it, and thus we would end up with a blank * Keyguard. */ - private void updateNotificationPanelTouchState() { + void updateNotificationPanelTouchState() { boolean goingToSleepWithoutAnimation = isGoingToSleep() && !mDozeParameters.shouldControlScreenOff(); - boolean disabled = (!mDeviceInteractive && !mPulsing) || goingToSleepWithoutAnimation; + boolean disabled = (!mDeviceInteractive && !mDozeServiceHost.isPulsing()) + || goingToSleepWithoutAnimation; mNotificationPanel.setTouchAndAnimationDisabled(disabled); mNotificationIconAreaController.setAnimationsEnabled(!disabled); } @@ -4025,7 +4016,7 @@ public class StatusBar extends SystemUI implements DemoMode, } public void notifyBiometricAuthModeChanged() { - updateDozing(); + mDozeServiceHost.updateDozing(); updateScrimController(); mStatusBarWindowViewController.onBiometricAuthModeChanged( mBiometricUnlockController.isWakeAndUnlock(), @@ -4061,7 +4052,7 @@ public class StatusBar extends SystemUI implements DemoMode, mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); } else if (mBrightnessMirrorVisible) { mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR); - } else if (isPulsing()) { + } else if (mDozeServiceHost.isPulsing()) { mScrimController.transitionTo(ScrimState.PULSING, mDozeScrimController.getScrimCallback()); } else if (mDozeServiceHost.hasPendingScreenOffCallback()) { @@ -4091,295 +4082,8 @@ public class StatusBar extends SystemUI implements DemoMode, return mStatusBarKeyguardViewManager.isShowing(); } - @VisibleForTesting - final class DozeServiceHost implements DozeHost { - private final ArrayList<Callback> mCallbacks = new ArrayList<>(); - private boolean mAnimateWakeup; - private boolean mAnimateScreenOff; - private boolean mIgnoreTouchWhilePulsing; - private Runnable mPendingScreenOffCallback; - @VisibleForTesting - boolean mWakeLockScreenPerformsAuth = SystemProperties.getBoolean( - "persist.sysui.wake_performs_auth", true); - - @Override - public String toString() { - return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]"; - } - - public void firePowerSaveChanged(boolean active) { - for (Callback callback : mCallbacks) { - callback.onPowerSaveChanged(active); - } - } - - public void fireNotificationPulse(NotificationEntry entry) { - Runnable pulseSupressedListener = () -> { - entry.setPulseSuppressed(true); - mNotificationIconAreaController.updateAodNotificationIcons(); - }; - for (Callback callback : mCallbacks) { - callback.onNotificationAlerted(pulseSupressedListener); - } - } - - @Override - public void addCallback(@NonNull Callback callback) { - mCallbacks.add(callback); - } - - @Override - public void removeCallback(@NonNull Callback callback) { - mCallbacks.remove(callback); - } - - @Override - public void startDozing() { - if (!mDozingRequested) { - mDozingRequested = true; - mDozeLog.traceDozing(mDozing); - updateDozing(); - updateIsKeyguard(); - } - } - - @Override - public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { - if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) { - mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, - "com.android.systemui:LONG_PRESS"); - startAssist(new Bundle()); - return; - } - - if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { - mScrimController.setWakeLockScreenSensorActive(true); - } - - if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) { - mStatusBarWindowViewController.suppressWakeUpGesture(true); - } - - boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN - && mWakeLockScreenPerformsAuth; - // Set the state to pulsing, so ScrimController will know what to do once we ask it to - // execute the transition. The pulse callback will then be invoked when the scrims - // are black, indicating that StatusBar is ready to present the rest of the UI. - mPulsing = true; - mDozeScrimController.pulse(new PulseCallback() { - @Override - public void onPulseStarted() { - callback.onPulseStarted(); - updateNotificationPanelTouchState(); - setPulsing(true); - } - - @Override - public void onPulseFinished() { - mPulsing = false; - callback.onPulseFinished(); - updateNotificationPanelTouchState(); - mScrimController.setWakeLockScreenSensorActive(false); - if (mStatusBarWindow != null) { - mStatusBarWindowViewController.suppressWakeUpGesture(false); - } - setPulsing(false); - } - - private void setPulsing(boolean pulsing) { - mStatusBarStateController.setPulsing(pulsing); - mStatusBarKeyguardViewManager.setPulsing(pulsing); - mKeyguardViewMediator.setPulsing(pulsing); - mNotificationPanel.setPulsing(pulsing); - mVisualStabilityManager.setPulsing(pulsing); - mStatusBarWindowViewController.setPulsing(pulsing); - mIgnoreTouchWhilePulsing = false; - if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) { - mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */); - } - updateScrimController(); - mPulseExpansionHandler.setPulsing(pulsing); - mWakeUpCoordinator.setPulsing(pulsing); - } - }, reason); - // DozeScrimController is in pulse state, now let's ask ScrimController to start - // pulsing and draw the black frame, if necessary. - updateScrimController(); - } - - @Override - public void stopDozing() { - if (mDozingRequested) { - mDozingRequested = false; - mDozeLog.traceDozing(mDozing); - updateDozing(); - } - } - - @Override - public void onIgnoreTouchWhilePulsing(boolean ignore) { - if (ignore != mIgnoreTouchWhilePulsing) { - mDozeLog.tracePulseTouchDisabledByProx(ignore); - } - mIgnoreTouchWhilePulsing = ignore; - if (isDozing() && ignore) { - mStatusBarWindowViewController.cancelCurrentTouch(); - } - } - - @Override - public void dozeTimeTick() { - mNotificationPanel.dozeTimeTick(); - if (mAmbientIndicationContainer instanceof DozeReceiver) { - ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick(); - } - } - - @Override - public boolean isPowerSaveActive() { - return mBatteryController.isAodPowerSave(); - } - - @Override - public boolean isPulsingBlocked() { - return mBiometricUnlockController.getMode() - == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; - } - - @Override - public boolean isProvisioned() { - return mDeviceProvisionedController.isDeviceProvisioned() - && mDeviceProvisionedController.isCurrentUserSetup(); - } - - @Override - public boolean isBlockingDoze() { - if (mBiometricUnlockController.hasPendingAuthentication()) { - Log.i(TAG, "Blocking AOD because fingerprint has authenticated"); - return true; - } - return false; - } - - @Override - public void extendPulse(int reason) { - if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { - mScrimController.setWakeLockScreenSensorActive(true); - } - if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) { - mHeadsUpManager.extendHeadsUp(); - } else { - mDozeScrimController.extendPulse(); - } - } - - @Override - public void stopPulsing() { - if (mDozeScrimController.isPulsing()) { - mDozeScrimController.pulseOutNow(); - } - } - - @Override - public void setAnimateWakeup(boolean animateWakeup) { - if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE - || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) { - // Too late to change the wakeup animation. - return; - } - mAnimateWakeup = animateWakeup; - } - - @Override - public void setAnimateScreenOff(boolean animateScreenOff) { - mAnimateScreenOff = animateScreenOff; - } - - @Override - public void onSlpiTap(float screenX, float screenY) { - if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null - && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) { - mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2); - float viewX = screenX - mTmpInt2[0]; - float viewY = screenY - mTmpInt2[1]; - if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth() - && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) { - dispatchTap(mAmbientIndicationContainer, viewX, viewY); - } - } - } - - @Override - public void setDozeScreenBrightness(int value) { - mStatusBarWindowController.setDozeScreenBrightness(value); - } - - @Override - public void setAodDimmingScrim(float scrimOpacity) { - mScrimController.setAodFrontScrimAlpha(scrimOpacity); - } - - @Override - public void prepareForGentleSleep(Runnable onDisplayOffCallback) { - if (mPendingScreenOffCallback != null) { - Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one."); - } - mPendingScreenOffCallback = onDisplayOffCallback; - updateScrimController(); - } - - @Override - public void cancelGentleSleep() { - mPendingScreenOffCallback = null; - if (mScrimController.getState() == ScrimState.OFF) { - updateScrimController(); - } - } - - /** - * When the dozing host is waiting for scrims to fade out to change the display state. - */ - boolean hasPendingScreenOffCallback() { - return mPendingScreenOffCallback != null; - } - - /** - * Executes an nullifies the pending display state callback. - * - * @see #hasPendingScreenOffCallback() - * @see #prepareForGentleSleep(Runnable) - */ - void executePendingScreenOffCallback() { - if (mPendingScreenOffCallback == null) { - return; - } - mPendingScreenOffCallback.run(); - mPendingScreenOffCallback = null; - } - - private void dispatchTap(View view, float x, float y) { - long now = SystemClock.elapsedRealtime(); - dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN); - dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP); - } - - private void dispatchTouchEvent(View view, float x, float y, long now, int action) { - MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */); - view.dispatchTouchEvent(ev); - ev.recycle(); - } - - private boolean shouldAnimateWakeup() { - return mAnimateWakeup; - } - - public boolean shouldAnimateScreenOff() { - return mAnimateScreenOff; - } - } - public boolean shouldIgnoreTouch() { - return isDozing() && mDozeServiceHost.mIgnoreTouchWhilePulsing; + return isDozing() && mDozeServiceHost.getIgnoreTouchWhilePulsing(); } // Begin Extra BaseStatusBar methods. @@ -4406,7 +4110,7 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mVisibleToUser; protected DevicePolicyManager mDevicePolicyManager; - protected PowerManager mPowerManager; + private final PowerManager mPowerManager; protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; protected KeyguardManager mKeyguardManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java new file mode 100644 index 000000000000..b05172c6d7c2 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.PowerManager; +import android.testing.AndroidTestingRunner; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.doze.DozeEvent; +import com.android.systemui.doze.DozeHost; +import com.android.systemui.doze.DozeLog; +import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; + +import dagger.Lazy; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class DozeServiceHostTest extends SysuiTestCase { + + private DozeServiceHost mDozeServiceHost; + + @Mock private HeadsUpManagerPhone mHeadsUpManager; + @Mock private ScrimController mScrimController; + @Mock private DozeScrimController mDozeScrimController; + @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; + @Mock private VisualStabilityManager mVisualStabilityManager; + @Mock private KeyguardViewMediator mKeyguardViewMediator; + @Mock private StatusBarStateControllerImpl mStatusBarStateController; + @Mock private BatteryController mBatteryController; + @Mock private DeviceProvisionedController mDeviceProvisionedController; + @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock private AssistManager mAssistManager; + @Mock private DozeLog mDozeLog; + @Mock private PulseExpansionHandler mPulseExpansionHandler; + @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; + @Mock private StatusBarWindowController mStatusBarWindowController; + @Mock private PowerManager mPowerManager; + @Mock private WakefulnessLifecycle mWakefullnessLifecycle; + @Mock private StatusBar mStatusBar; + @Mock private NotificationIconAreaController mNotificationIconAreaController; + @Mock private StatusBarWindowViewController mStatusBarWindowViewController; + @Mock private StatusBarWindowView mStatusBarWindow; + @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + @Mock private NotificationPanelView mNotificationPanel; + @Mock private View mAmbientIndicationContainer; + @Mock private BiometricUnlockController mBiometricUnlockController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController); + mDozeServiceHost = new DozeServiceHost(mDozeLog, mPowerManager, mWakefullnessLifecycle, + mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager, + mBatteryController, mScrimController, mBiometricUnlockControllerLazy, + mKeyguardViewMediator, mAssistManager, mDozeScrimController, mKeyguardUpdateMonitor, + mVisualStabilityManager, mPulseExpansionHandler, mStatusBarWindowController, + mNotificationWakeUpCoordinator); + + mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController, + mStatusBarWindowViewController, mStatusBarWindow, mStatusBarKeyguardViewManager, + mNotificationPanel, mAmbientIndicationContainer); + } + + @Test + public void testStartStopDozing() { + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); + when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true); + + assertFalse(mDozeServiceHost.getDozingRequested()); + + mDozeServiceHost.startDozing(); + verify(mStatusBarStateController).setIsDozing(eq(true)); + verify(mStatusBar).updateIsKeyguard(); + + mDozeServiceHost.stopDozing(); + verify(mStatusBarStateController).setIsDozing(eq(false)); + } + + + @Test + public void testPulseWhileDozing_updatesScrimController() { + mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); + mStatusBar.showKeyguardImpl(); + + // Keep track of callback to be able to stop the pulse +// DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1]; +// doAnswer(invocation -> { +// pulseCallback[0] = invocation.getArgument(0); +// return null; +// }).when(mDozeScrimController).pulse(any(), anyInt()); + + // Starting a pulse should change the scrim controller to the pulsing state + mDozeServiceHost.pulseWhileDozing(new DozeHost.PulseCallback() { + @Override + public void onPulseStarted() { + } + + @Override + public void onPulseFinished() { + } + }, DozeEvent.PULSE_REASON_NOTIFICATION); + + ArgumentCaptor<DozeHost.PulseCallback> pulseCallbackArgumentCaptor = + ArgumentCaptor.forClass(DozeHost.PulseCallback.class); + + verify(mDozeScrimController).pulse( + pulseCallbackArgumentCaptor.capture(), eq(DozeEvent.PULSE_REASON_NOTIFICATION)); + verify(mStatusBar).updateScrimController(); + reset(mStatusBar); + + pulseCallbackArgumentCaptor.getValue().onPulseFinished(); + assertFalse(mDozeScrimController.isPulsing()); + verify(mStatusBar).updateScrimController(); + } + + + @Test + public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() { + // Keep track of callback to be able to stop the pulse + final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1]; + doAnswer(invocation -> { + pulseCallback[0] = invocation.getArgument(0); + return null; + }).when(mDozeScrimController).pulse(any(), anyInt()); + + // Starting a pulse while docking should suppress wakeup gesture + mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), + DozeEvent.PULSE_REASON_DOCKING); + verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(true)); + + // Ending a pulse should restore wakeup gesture + pulseCallback[0].onPulseFinished(); + verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(false)); + } + + @Test + public void testPulseWhileDozing_notifyAuthInterrupt() { + HashSet<Integer> reasonsWantingAuth = new HashSet<>( + Collections.singletonList(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); + HashSet<Integer> reasonsSkippingAuth = new HashSet<>( + Arrays.asList(DozeEvent.PULSE_REASON_INTENT, + DozeEvent.PULSE_REASON_NOTIFICATION, + DozeEvent.PULSE_REASON_SENSOR_SIGMOTION, + DozeEvent.REASON_SENSOR_PICKUP, + DozeEvent.REASON_SENSOR_DOUBLE_TAP, + DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, + DozeEvent.PULSE_REASON_DOCKING, + DozeEvent.REASON_SENSOR_WAKE_UP, + DozeEvent.REASON_SENSOR_TAP)); + HashSet<Integer> reasonsThatDontPulse = new HashSet<>( + Arrays.asList(DozeEvent.REASON_SENSOR_PICKUP, + DozeEvent.REASON_SENSOR_DOUBLE_TAP, + DozeEvent.REASON_SENSOR_TAP)); + + doAnswer(invocation -> { + DozeHost.PulseCallback callback = invocation.getArgument(0); + callback.onPulseStarted(); + return null; + }).when(mDozeScrimController).pulse(any(), anyInt()); + + mDozeServiceHost.mWakeLockScreenPerformsAuth = true; + for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { + reset(mKeyguardUpdateMonitor); + mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i); + if (reasonsWantingAuth.contains(i)) { + verify(mKeyguardUpdateMonitor).onAuthInterruptDetected(eq(true)); + } else if (reasonsSkippingAuth.contains(i) || reasonsThatDontPulse.contains(i)) { + verify(mKeyguardUpdateMonitor, never()).onAuthInterruptDetected(eq(true)); + } else { + throw new AssertionError("Reason " + i + " isn't specified as wanting or skipping" + + " passive auth. Please consider how this pulse reason should behave."); + } + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index f5e92e4f3181..66c01ca58491 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -85,8 +85,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.doze.DozeEvent; -import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; @@ -145,9 +143,6 @@ import org.mockito.MockitoAnnotations; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import dagger.Lazy; @@ -231,6 +226,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private DozeParameters mDozeParameters; @Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy; @Mock private LockscreenWallpaper mLockscreenWallpaper; + @Mock private DozeServiceHost mDozeServiceHost; @Mock private LinearLayout mLockIconContainer; @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback; @@ -365,7 +361,10 @@ public class StatusBarTest extends SysuiTestCase { mDozeParameters, mScrimController, mLockscreenWallpaperLazy, - mBiometricUnlockControllerLazy); + mBiometricUnlockControllerLazy, + mDozeServiceHost, + mPowerManager, + mDozeScrimController); when(mStatusBarWindowView.findViewById(R.id.lock_icon_container)).thenReturn( mLockIconContainer); @@ -388,7 +387,6 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar.mNotificationIconAreaController = mNotificationIconAreaController; mStatusBar.mPresenter = mNotificationPresenter; mStatusBar.mKeyguardIndicationController = mKeyguardIndicationController; - mStatusBar.mPowerManager = mPowerManager; mStatusBar.mBarService = mBarService; mStatusBar.mStackScroller = mStackScroller; mStatusBar.mStatusBarWindowViewController = mStatusBarWindowViewController; @@ -757,83 +755,18 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); mStatusBar.showKeyguardImpl(); - // Keep track of callback to be able to stop the pulse - DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1]; - doAnswer(invocation -> { - pulseCallback[0] = invocation.getArgument(0); - return null; - }).when(mDozeScrimController).pulse(any(), anyInt()); - // Starting a pulse should change the scrim controller to the pulsing state - mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), - DozeEvent.PULSE_REASON_NOTIFICATION); + when(mDozeServiceHost.isPulsing()).thenReturn(true); + mStatusBar.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.PULSING), any()); // Ending a pulse should take it back to keyguard state - pulseCallback[0].onPulseFinished(); + when(mDozeServiceHost.isPulsing()).thenReturn(false); + mStatusBar.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD)); } @Test - public void testPulseWhileDozing_notifyAuthInterrupt() { - HashSet<Integer> reasonsWantingAuth = new HashSet<>( - Collections.singletonList(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); - HashSet<Integer> reasonsSkippingAuth = new HashSet<>( - Arrays.asList(DozeEvent.PULSE_REASON_INTENT, - DozeEvent.PULSE_REASON_NOTIFICATION, - DozeEvent.PULSE_REASON_SENSOR_SIGMOTION, - DozeEvent.REASON_SENSOR_PICKUP, - DozeEvent.REASON_SENSOR_DOUBLE_TAP, - DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, - DozeEvent.PULSE_REASON_DOCKING, - DozeEvent.REASON_SENSOR_WAKE_UP, - DozeEvent.REASON_SENSOR_TAP)); - HashSet<Integer> reasonsThatDontPulse = new HashSet<>( - Arrays.asList(DozeEvent.REASON_SENSOR_PICKUP, - DozeEvent.REASON_SENSOR_DOUBLE_TAP, - DozeEvent.REASON_SENSOR_TAP)); - - doAnswer(invocation -> { - DozeHost.PulseCallback callback = invocation.getArgument(0); - callback.onPulseStarted(); - return null; - }).when(mDozeScrimController).pulse(any(), anyInt()); - - mStatusBar.mDozeServiceHost.mWakeLockScreenPerformsAuth = true; - for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { - reset(mKeyguardUpdateMonitor); - mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i); - if (reasonsWantingAuth.contains(i)) { - verify(mKeyguardUpdateMonitor).onAuthInterruptDetected(eq(true)); - } else if (reasonsSkippingAuth.contains(i) || reasonsThatDontPulse.contains(i)) { - verify(mKeyguardUpdateMonitor, never()).onAuthInterruptDetected(eq(true)); - } else { - throw new AssertionError("Reason " + i + " isn't specified as wanting or skipping" - + " passive auth. Please consider how this pulse reason should behave."); - } - } - } - - @Test - public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() { - // Keep track of callback to be able to stop the pulse - final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1]; - doAnswer(invocation -> { - pulseCallback[0] = invocation.getArgument(0); - return null; - }).when(mDozeScrimController).pulse(any(), anyInt()); - - // Starting a pulse while docking should suppress wakeup gesture - mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), - DozeEvent.PULSE_REASON_DOCKING); - verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(true)); - - // Ending a pulse should restore wakeup gesture - pulseCallback[0].onPulseFinished(); - verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(false)); - } - - @Test public void testSetState_changesIsFullScreenUserSwitcherState() { mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); assertFalse(mStatusBar.isFullScreenUserSwitcherState()); @@ -859,27 +792,17 @@ public class StatusBarTest extends SysuiTestCase { } @Test - public void testStartStopDozing() { - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); - when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true); - - mStatusBar.mDozeServiceHost.startDozing(); - verify(mStatusBarStateController).setIsDozing(eq(true)); - - mStatusBar.mDozeServiceHost.stopDozing(); - verify(mStatusBarStateController).setIsDozing(eq(false)); - } - - @Test public void testOnStartedWakingUp_isNotDozing() { mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true); - mStatusBar.mDozeServiceHost.startDozing(); - verify(mStatusBarStateController).setIsDozing(eq(true)); + when(mDozeServiceHost.getDozingRequested()).thenReturn(true); + mStatusBar.updateIsKeyguard(); + // TODO: mNotificationPanelView.expand(false) gets called twice. Should be once. + verify(mNotificationPanelView, times(2)).expand(eq(false)); clearInvocations(mNotificationPanelView); mStatusBar.mWakefulnessObserver.onStartedWakingUp(); - verify(mStatusBarStateController).setIsDozing(eq(false)); + verify(mDozeServiceHost).stopDozing(); verify(mNotificationPanelView).expand(eq(false)); } @@ -887,7 +810,8 @@ public class StatusBarTest extends SysuiTestCase { public void testOnStartedWakingUp_doesNotDismissBouncer_whenPulsing() { mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true); - mStatusBar.mDozeServiceHost.startDozing(); + when(mDozeServiceHost.getDozingRequested()).thenReturn(true); + mStatusBar.updateIsKeyguard(); clearInvocations(mNotificationPanelView); mStatusBar.setBouncerShowing(true); |