Merge "Refactor doze suppressors into its own class" into tm-dev

This commit is contained in:
TreeHugger Robot 2022-02-27 18:08:39 +00:00 committed by Android (Google) Code Review
commit 95db721b82
11 changed files with 523 additions and 103 deletions

View File

@ -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 {

View File

@ -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) {

View File

@ -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"
})
}

View File

@ -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);

View File

@ -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<BiometricUnlockController> mBiometricUnlockControllerLazy;
private boolean mBroadcastReceiverRegistered;
@Inject
public DozeSuppressor(
DozeHost dozeHost,
AmbientDisplayConfiguration config,
DozeLog dozeLog,
BroadcastDispatcher broadcastDispatcher,
UiModeManager uiModeManager,
Lazy<BiometricUnlockController> 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);
}
};
}

View File

@ -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);
}
};
}

View File

@ -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;
}
}

View File

@ -534,7 +534,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
@Override
public void suppressAmbientDisplay(boolean suppressed) {
mDozeServiceHost.setDozeSuppressed(suppressed);
mDozeServiceHost.setAlwaysOnSuppressed(suppressed);
}
@Override

View File

@ -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);

View File

@ -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<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock
private BiometricUnlockController mBiometricUnlockController;
@Mock
private DozeMachine mDozeMachine;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
private BroadcastReceiver mBroadcastReceiver;
@Captor
private ArgumentCaptor<DozeHost.Callback> 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();
}
}

View File

@ -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);
}