diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index 2beed4c6a7e7..d89c0be26351 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -31,7 +31,6 @@ public interface DozeHost { boolean isPowerSaveActive(); boolean isPulsingBlocked(); boolean isProvisioned(); - boolean isBlockingDoze(); /** * Makes a current pulse last for twice as long. @@ -80,8 +79,9 @@ public interface DozeHost { */ void stopPulsing(); - /** Returns whether doze is suppressed. */ - boolean isDozeSuppressed(); + /** Returns whether always-on-display is suppressed. This does not include suppressing + * wake-up gestures. */ + boolean isAlwaysOnSuppressed(); interface Callback { /** @@ -97,8 +97,10 @@ public interface DozeHost { */ default void onPowerSaveChanged(boolean active) {} - /** Called when the doze suppression state changes. */ - default void onDozeSuppressedChanged(boolean suppressed) {} + /** + * Called when the always on suppression state changes. See {@link #isAlwaysOnSuppressed()}. + */ + default void onAlwaysOnSuppressedChanged(boolean suppressed) {} } interface PulseCallback { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 25115200ba19..0a2e69f943c6 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -131,14 +131,6 @@ public class DozeLog implements Dumpable { mLogger.logDozingChanged(dozing); } - /** - * Appends dozing event to the logs - * @param suppressed true if dozing is suppressed - */ - public void traceDozingSuppressed(boolean suppressed) { - mLogger.logDozingSuppressed(suppressed); - } - /** * Appends fling event to the logs */ @@ -325,15 +317,40 @@ public class DozeLog implements Dumpable { } /** - * Appends doze suppressed event to the logs + * Appends the doze state that was suppressed to the doze event log * @param suppressedState The {@link DozeMachine.State} that was suppressed */ - public void traceDozeSuppressed(DozeMachine.State suppressedState) { - mLogger.logDozeSuppressed(suppressedState); + public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState) { + mLogger.logAlwaysOnSuppressed(suppressedState); } /** - * Appends new AOD sreen brightness to logs + * Appends reason why doze immediately ended. + */ + public void traceImmediatelyEndDoze(String reason) { + mLogger.logImmediatelyEndDoze(reason); + } + + /** + * Appends power save changes that may cause a new doze state + * @param powerSaveActive true if power saving is active + * @param nextState the state that we'll transition to + */ + public void tracePowerSaveChanged(boolean powerSaveActive, DozeMachine.State nextState) { + mLogger.logPowerSaveChanged(powerSaveActive, nextState); + } + + /** + * Appends an event on AOD suppression change + * @param suppressed true if AOD is being suppressed + * @param nextState the state that we'll transition to + */ + public void traceAlwaysOnSuppressedChange(boolean suppressed, DozeMachine.State nextState) { + mLogger.logAlwaysOnSuppressedChange(suppressed, nextState); + } + + /** + * Appends new AOD screen brightness to logs * @param brightness display brightness setting */ public void traceDozeScreenBrightness(int brightness) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index 4ba6b51c83c8..f3f6be210fed 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -74,11 +74,21 @@ class DozeLogger @Inject constructor( }) } - fun logDozingSuppressed(isDozingSuppressed: Boolean) { + fun logPowerSaveChanged(powerSaveActive: Boolean, nextState: DozeMachine.State) { buffer.log(TAG, INFO, { - bool1 = isDozingSuppressed + bool1 = powerSaveActive + str1 = nextState.name }, { - "DozingSuppressed=$bool1" + "Power save active=$bool1 nextState=$str1" + }) + } + + fun logAlwaysOnSuppressedChange(isAodSuppressed: Boolean, nextState: DozeMachine.State) { + buffer.log(TAG, INFO, { + bool1 = isAodSuppressed + str1 = nextState.name + }, { + "Always on (AOD) suppressed changed, suppressed=$bool1 nextState=$str1" }) } @@ -257,11 +267,19 @@ class DozeLogger @Inject constructor( }) } - fun logDozeSuppressed(state: DozeMachine.State) { + fun logAlwaysOnSuppressed(state: DozeMachine.State) { buffer.log(TAG, INFO, { str1 = state.name }, { - "Doze state suppressed, state=$str1" + "Always-on state suppressed, suppressed state=$str1" + }) + } + + fun logImmediatelyEndDoze(reason: String) { + buffer.log(TAG, INFO, { + str1 = reason + }, { + "Doze immediately ended due to $str1" }) } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 789ad6223e79..ae01f0ad84c7 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -357,9 +357,9 @@ public class DozeMachine { if (mState == State.FINISH) { return State.FINISH; } - if (mDozeHost.isDozeSuppressed() && requestedState.isAlwaysOn()) { + if (mDozeHost.isAlwaysOnSuppressed() && requestedState.isAlwaysOn()) { Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState); - mDozeLog.traceDozeSuppressed(requestedState); + mDozeLog.traceAlwaysOnSuppressed(requestedState); return State.DOZE; } if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING @@ -415,7 +415,6 @@ public class DozeMachine { pw.print(" state="); pw.println(mState); pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState); pw.print(" wakeLock="); pw.println(mWakeLock); - pw.print(" isDozeSuppressed="); pw.println(mDozeHost.isDozeSuppressed()); pw.println("Parts:"); for (Part p : mParts) { p.dump(pw); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java new file mode 100644 index 000000000000..31d43b5475e0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2022 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.doze; + +import static android.app.UiModeManager.ACTION_ENTER_CAR_MODE; + +import android.app.UiModeManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.hardware.display.AmbientDisplayConfiguration; +import android.os.PowerManager; +import android.os.UserHandle; +import android.text.TextUtils; + +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.doze.dagger.DozeScope; +import com.android.systemui.statusbar.phone.BiometricUnlockController; + +import java.io.PrintWriter; + +import javax.inject.Inject; + +import dagger.Lazy; + +/** + * Handles suppressing doze on: + * 1. INITIALIZED, don't allow dozing at all when: + * - in CAR_MODE + * - device is NOT provisioned + * - there's a pending authentication + * 2. PowerSaveMode active + * - no always-on-display (DOZE_AOD) + * - continues to allow doze triggers (DOZE, DOZE_REQUEST_PULSE) + * 3. Suppression changes from the PowerManager API. See {@link PowerManager#suppressAmbientDisplay} + * and {@link DozeHost#isAlwaysOnSuppressed()}. + * - no always-on-display (DOZE_AOD) + * - allow doze triggers (DOZE), but disallow notifications (handled by {@link DozeTriggers}) + * - See extra check in {@link DozeMachine} to guarantee device never enters always-on states + */ +@DozeScope +public class DozeSuppressor implements DozeMachine.Part { + private static final String TAG = "DozeSuppressor"; + + private DozeMachine mMachine; + private final DozeHost mDozeHost; + private final AmbientDisplayConfiguration mConfig; + private final DozeLog mDozeLog; + private final BroadcastDispatcher mBroadcastDispatcher; + private final UiModeManager mUiModeManager; + private final Lazy mBiometricUnlockControllerLazy; + + private boolean mBroadcastReceiverRegistered; + + @Inject + public DozeSuppressor( + DozeHost dozeHost, + AmbientDisplayConfiguration config, + DozeLog dozeLog, + BroadcastDispatcher broadcastDispatcher, + UiModeManager uiModeManager, + Lazy biometricUnlockControllerLazy) { + mDozeHost = dozeHost; + mConfig = config; + mDozeLog = dozeLog; + mBroadcastDispatcher = broadcastDispatcher; + mUiModeManager = uiModeManager; + mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; + } + + @Override + public void setDozeMachine(DozeMachine dozeMachine) { + mMachine = dozeMachine; + } + + @Override + public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { + switch (newState) { + case INITIALIZED: + registerBroadcastReceiver(); + mDozeHost.addCallback(mHostCallback); + checkShouldImmediatelyEndDoze(); + break; + case FINISH: + destroy(); + break; + default: + } + } + + @Override + public void destroy() { + unregisterBroadcastReceiver(); + mDozeHost.removeCallback(mHostCallback); + } + + private void checkShouldImmediatelyEndDoze() { + String reason = null; + if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) { + reason = "car_mode"; + } else if (!mDozeHost.isProvisioned()) { + reason = "device_unprovisioned"; + } else if (mBiometricUnlockControllerLazy.get().hasPendingAuthentication()) { + reason = "has_pending_auth"; + } + + if (!TextUtils.isEmpty(reason)) { + mDozeLog.traceImmediatelyEndDoze(reason); + mMachine.requestState(DozeMachine.State.FINISH); + } + } + + @Override + public void dump(PrintWriter pw) { + pw.println(" uiMode=" + mUiModeManager.getCurrentModeType()); + pw.println(" hasPendingAuth=" + + mBiometricUnlockControllerLazy.get().hasPendingAuthentication()); + pw.println(" isProvisioned=" + mDozeHost.isProvisioned()); + pw.println(" isAlwaysOnSuppressed=" + mDozeHost.isAlwaysOnSuppressed()); + pw.println(" aodPowerSaveActive=" + mDozeHost.isPowerSaveActive()); + } + + private void registerBroadcastReceiver() { + if (mBroadcastReceiverRegistered) { + return; + } + IntentFilter filter = new IntentFilter(ACTION_ENTER_CAR_MODE); + mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter); + mBroadcastReceiverRegistered = true; + } + + private void unregisterBroadcastReceiver() { + if (!mBroadcastReceiverRegistered) { + return; + } + mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); + mBroadcastReceiverRegistered = false; + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { + mDozeLog.traceImmediatelyEndDoze("car_mode"); + mMachine.requestState(DozeMachine.State.FINISH); + } + } + }; + + private DozeHost.Callback mHostCallback = new DozeHost.Callback() { + @Override + public void onPowerSaveChanged(boolean active) { + DozeMachine.State nextState = null; + if (mDozeHost.isPowerSaveActive()) { + nextState = DozeMachine.State.DOZE; + } else if (mMachine.getState() == DozeMachine.State.DOZE + && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) { + nextState = DozeMachine.State.DOZE_AOD; + } + + if (nextState != null) { + mDozeLog.tracePowerSaveChanged(mDozeHost.isPowerSaveActive(), nextState); + mMachine.requestState(nextState); + } + } + + @Override + public void onAlwaysOnSuppressedChanged(boolean suppressed) { + final DozeMachine.State nextState; + if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) { + nextState = DozeMachine.State.DOZE_AOD; + } else { + nextState = DozeMachine.State.DOZE; + } + mDozeLog.traceAlwaysOnSuppressedChange(suppressed, nextState); + mMachine.requestState(nextState); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 8bff3ba0b6ba..74044e2c2eb8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -17,12 +17,10 @@ package com.android.systemui.doze; import android.annotation.Nullable; -import android.app.UiModeManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Configuration; import android.hardware.display.AmbientDisplayConfiguration; import android.os.SystemClock; import android.os.UserHandle; @@ -88,7 +86,6 @@ public class DozeTriggers implements DozeMachine.Part { private final AsyncSensorManager mSensorManager; private final WakeLock mWakeLock; private final boolean mAllowPulseTriggers; - private final UiModeManager mUiModeManager; private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver(); private final DockEventListener mDockEventListener = new DockEventListener(); private final DockManager mDockManager; @@ -203,8 +200,6 @@ public class DozeTriggers implements DozeMachine.Part { mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor, secureSettings, authController, devicePostureController); - - mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; mProxCheck = proxCheck; mDozeLog = dozeLog; @@ -247,7 +242,7 @@ public class DozeTriggers implements DozeMachine.Part { mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); return; } - if (mDozeHost.isDozeSuppressed()) { + if (mDozeHost.isAlwaysOnSuppressed()) { runIfNotNull(onPulseSuppressedListener); mDozeLog.tracePulseDropped("dozeSuppressed"); return; @@ -456,10 +451,9 @@ public class DozeTriggers implements DozeMachine.Part { mAodInterruptRunnable = null; sWakeDisplaySensorState = true; mBroadcastReceiver.register(mBroadcastDispatcher); - mDozeHost.addCallback(mHostCallback); mDockManager.addListener(mDockEventListener); mDozeSensors.requestTemporaryDisable(); - checkTriggersAtInit(); + mDozeHost.addCallback(mHostCallback); break; case DOZE: case DOZE_AOD: @@ -516,15 +510,6 @@ public class DozeTriggers implements DozeMachine.Part { } } - - private void checkTriggersAtInit() { - if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR - || mDozeHost.isBlockingDoze() - || !mDozeHost.isProvisioned()) { - mMachine.requestState(DozeMachine.State.FINISH); - } - } - private void requestPulse(final int reason, boolean performedProxCheck, Runnable onPulseSuppressedListener) { Assert.isMainThread(); @@ -608,9 +593,6 @@ public class DozeTriggers implements DozeMachine.Part { requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */ null /* onPulseSuppressedListener */); } - if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { - mMachine.requestState(DozeMachine.State.FINISH); - } if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { mDozeSensors.onUserSwitched(); } @@ -621,7 +603,6 @@ public class DozeTriggers implements DozeMachine.Part { return; } IntentFilter filter = new IntentFilter(PULSE_ACTION); - filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); filter.addAction(Intent.ACTION_USER_SWITCHED); broadcastDispatcher.registerReceiver(this, filter); mRegistered = true; @@ -659,26 +640,5 @@ public class DozeTriggers implements DozeMachine.Part { public void onNotificationAlerted(Runnable onPulseSuppressedListener) { onNotification(onPulseSuppressedListener); } - - @Override - public void onPowerSaveChanged(boolean active) { - if (mDozeHost.isPowerSaveActive()) { - mMachine.requestState(DozeMachine.State.DOZE); - } else if (mMachine.getState() == DozeMachine.State.DOZE - && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) { - mMachine.requestState(DozeMachine.State.DOZE_AOD); - } - } - - @Override - public void onDozeSuppressedChanged(boolean suppressed) { - final DozeMachine.State nextState; - if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) { - nextState = DozeMachine.State.DOZE_AOD; - } else { - nextState = DozeMachine.State.DOZE; - } - mMachine.requestState(nextState); - } }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index 05fba5498ea7..696c5a760bf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -98,7 +98,7 @@ public final class DozeServiceHost implements DozeHost { private NotificationPanelViewController mNotificationPanel; private View mAmbientIndicationContainer; private StatusBar mStatusBar; - private boolean mSuppressed; + private boolean mAlwaysOnSuppressed; @Inject public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager, @@ -331,15 +331,6 @@ public final class DozeServiceHost implements DozeHost { && mDeviceProvisionedController.isCurrentUserSetup(); } - @Override - public boolean isBlockingDoze() { - if (mBiometricUnlockControllerLazy.get().hasPendingAuthentication()) { - Log.i(StatusBar.TAG, "Blocking AOD because fingerprint has authenticated"); - return true; - } - return false; - } - @Override public void extendPulse(int reason) { if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { @@ -452,18 +443,25 @@ public final class DozeServiceHost implements DozeHost { return mIgnoreTouchWhilePulsing; } - void setDozeSuppressed(boolean suppressed) { - if (suppressed == mSuppressed) { + /** + * Suppresses always-on-display and waking up the display for notifications. + * Does not disable wakeup gestures like pickup and tap. + */ + void setAlwaysOnSuppressed(boolean suppressed) { + if (suppressed == mAlwaysOnSuppressed) { return; } - mSuppressed = suppressed; - mDozeLog.traceDozingSuppressed(mSuppressed); + mAlwaysOnSuppressed = suppressed; for (Callback callback : mCallbacks) { - callback.onDozeSuppressedChanged(suppressed); + callback.onAlwaysOnSuppressedChanged(suppressed); } } - public boolean isDozeSuppressed() { - return mSuppressed; + /** + * Whether always-on-display is being suppressed. This does not affect wakeup gestures like + * pickup and tap. + */ + public boolean isAlwaysOnSuppressed() { + return mAlwaysOnSuppressed; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java index aeb782660173..883445e17162 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java @@ -534,7 +534,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void suppressAmbientDisplay(boolean suppressed) { - mDozeServiceHost.setDozeSuppressed(suppressed); + mDozeServiceHost.setAlwaysOnSuppressed(suppressed); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index 56844292ce4a..3340f2fd5749 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -143,8 +143,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnDisabled_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnDisabled_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); mMachine.requestState(INITIALIZED); @@ -154,8 +154,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnEnabled_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnEnabled_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); @@ -165,8 +165,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_afterDocked_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_afterDocked_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); @@ -176,8 +176,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); @@ -189,8 +189,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); @@ -228,8 +228,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testPulseDone_dozeSuppressed_goesToSuppressed() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testPulseDone_alwaysOnSuppressed_goesToSuppressed() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); @@ -266,8 +266,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testPulseDone_alwaysOnSuppressed_afterDocked_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); @@ -295,8 +295,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testPulseDone_dozeSuppressed_afterDockPaused_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testPulseDone_alwaysOnSuppressed_afterDockPaused_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java new file mode 100644 index 000000000000..aa0a909622bb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2022 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 andatest + * limitations under the License. + */ + +package com.android.systemui.doze; + +import static com.android.systemui.doze.DozeMachine.State.DOZE; +import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD; +import static com.android.systemui.doze.DozeMachine.State.FINISH; +import static com.android.systemui.doze.DozeMachine.State.INITIALIZED; +import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED; + +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.UiModeManager; +import android.content.BroadcastReceiver; +import android.content.res.Configuration; +import android.hardware.display.AmbientDisplayConfiguration; +import android.testing.AndroidTestingRunner; +import android.testing.UiThreadTest; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.statusbar.phone.BiometricUnlockController; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import dagger.Lazy; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@UiThreadTest +public class DozeSuppressorTest extends SysuiTestCase { + + DozeSuppressor mDozeSuppressor; + @Mock + private DozeLog mDozeLog; + @Mock + private DozeHost mDozeHost; + @Mock + private AmbientDisplayConfiguration mConfig; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; + @Mock + private UiModeManager mUiModeManager; + @Mock + private Lazy mBiometricUnlockControllerLazy; + @Mock + private BiometricUnlockController mBiometricUnlockController; + + @Mock + private DozeMachine mDozeMachine; + + @Captor + private ArgumentCaptor mBroadcastReceiverCaptor; + private BroadcastReceiver mBroadcastReceiver; + + @Captor + private ArgumentCaptor mDozeHostCaptor; + private DozeHost.Callback mDozeHostCallback; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + // setup state for NOT ending doze immediately + when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController); + when(mBiometricUnlockController.hasPendingAuthentication()).thenReturn(false); + when(mDozeHost.isProvisioned()).thenReturn(true); + + mDozeSuppressor = new DozeSuppressor( + mDozeHost, + mConfig, + mDozeLog, + mBroadcastDispatcher, + mUiModeManager, + mBiometricUnlockControllerLazy); + + mDozeSuppressor.setDozeMachine(mDozeMachine); + } + + @After + public void tearDown() { + mDozeSuppressor.destroy(); + } + + @Test + public void testRegistersListenersOnInitialized_unregisteredOnFinish() { + // check that receivers and callbacks registered + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + captureBroadcastReceiver(); + captureDozeHostCallback(); + + // check that receivers and callbacks are unregistered + mDozeSuppressor.transitionTo(INITIALIZED, FINISH); + verify(mBroadcastDispatcher).unregisterReceiver(mBroadcastReceiver); + verify(mDozeHost).removeCallback(mDozeHostCallback); + } + + @Test + public void testEndDoze_carMode() { + // GIVEN car mode + when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR); + + // WHEN dozing begins + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + + // THEN doze immediately ends + verify(mDozeMachine).requestState(FINISH); + } + + @Test + public void testEndDoze_unprovisioned() { + // GIVEN device unprovisioned + when(mDozeHost.isProvisioned()).thenReturn(false); + + // WHEN dozing begins + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + + // THEN doze immediately ends + verify(mDozeMachine).requestState(FINISH); + } + + @Test + public void testEndDoze_hasPendingUnlock() { + // GIVEN device unprovisioned + when(mBiometricUnlockController.hasPendingAuthentication()).thenReturn(true); + + // WHEN dozing begins + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + + // THEN doze immediately ends + verify(mDozeMachine).requestState(FINISH); + } + + @Test + public void testPowerSaveChanged_active() { + // GIVEN AOD power save is active and doze is initialized + when(mDozeHost.isPowerSaveActive()).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + captureDozeHostCallback(); + + // WHEN power save change gets triggered (even if active = false, since it + // may differ from the aodPowerSaveActive state reported by DostHost) + mDozeHostCallback.onPowerSaveChanged(false); + + // THEN the state changes to DOZE + verify(mDozeMachine).requestState(DOZE); + } + + @Test + public void testPowerSaveChanged_notActive() { + // GIVEN DOZE (not showing aod content) + when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + when(mDozeMachine.getState()).thenReturn(DOZE); + captureDozeHostCallback(); + + // WHEN power save mode is no longer active + when(mDozeHost.isPowerSaveActive()).thenReturn(false); + mDozeHostCallback.onPowerSaveChanged(false); + + // THEN the state changes to DOZE_AOD + verify(mDozeMachine).requestState(DOZE_AOD); + } + + @Test + public void testAlwaysOnSuppressedChanged_nowSuppressed() { + // GIVEN DOZE_AOD + when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + when(mDozeMachine.getState()).thenReturn(DOZE_AOD); + captureDozeHostCallback(); + + // WHEN alwaysOnSuppressedChanged to suppressed=true + mDozeHostCallback.onAlwaysOnSuppressedChanged(true); + + // THEN DOZE requested + verify(mDozeMachine).requestState(DOZE); + } + + @Test + public void testAlwaysOnSuppressedChanged_notSuppressed() { + // GIVEN DOZE + when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + when(mDozeMachine.getState()).thenReturn(DOZE); + captureDozeHostCallback(); + + // WHEN alwaysOnSuppressedChanged to suppressed=false + mDozeHostCallback.onAlwaysOnSuppressedChanged(false); + + // THEN DOZE_AOD requested + verify(mDozeMachine).requestState(DOZE_AOD); + } + + private void captureDozeHostCallback() { + verify(mDozeHost).addCallback(mDozeHostCaptor.capture()); + mDozeHostCallback = mDozeHostCaptor.getValue(); + } + + private void captureBroadcastReceiver() { + verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), + anyObject()); + mBroadcastReceiver = mBroadcastReceiverCaptor.getValue(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java index 25950f2e8caa..54d9cece90fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java @@ -158,13 +158,13 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { @Test public void testSuppressAmbientDisplay_suppress() { mSbcqCallbacks.suppressAmbientDisplay(true); - verify(mDozeServiceHost).setDozeSuppressed(true); + verify(mDozeServiceHost).setAlwaysOnSuppressed(true); } @Test public void testSuppressAmbientDisplay_unsuppress() { mSbcqCallbacks.suppressAmbientDisplay(false); - verify(mDozeServiceHost).setDozeSuppressed(false); + verify(mDozeServiceHost).setAlwaysOnSuppressed(false); }