Loading core/java/android/os/PowerManager.java +9 −0 Original line number Diff line number Diff line Loading @@ -687,6 +687,7 @@ public final class PowerManager { WAKE_REASON_LIFT, WAKE_REASON_BIOMETRIC, WAKE_REASON_DOCK, WAKE_REASON_DOZE_STOPPED, }) @Retention(RetentionPolicy.SOURCE) public @interface WakeReason{} Loading Loading @@ -833,6 +834,13 @@ public final class PowerManager { */ public static final int WAKE_REASON_DOCK = 18; /** * Wake up reason code: Waking the dream because the dozing was stopped directly through dream * APIs rather than some other more specific reason. * @hide */ public static final int WAKE_REASON_DOZE_STOPPED = 19; /** * Convert the wake reason to a string for debugging purposes. * @hide Loading @@ -858,6 +866,7 @@ public final class PowerManager { case WAKE_REASON_LIFT: return "WAKE_REASON_LIFT"; case WAKE_REASON_BIOMETRIC: return "WAKE_REASON_BIOMETRIC"; case WAKE_REASON_DOCK: return "WAKE_REASON_DOCK"; case WAKE_REASON_DOZE_STOPPED: return "WAKE_REASON_DOZE_STOPPED"; default: return Integer.toString(wakeReason); } } Loading core/java/android/service/dreams/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -140,3 +140,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "wake_on_stopping_doze" namespace: "systemui" description: "Sends a wakeUp when explicitly stopping the doze dream" bug: "298073718" metadata { purpose: PURPOSE_BUGFIX } } services/core/java/com/android/server/dreams/DreamManagerService.java +67 −15 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.service.dreams.Flags.cleanupDreamSettingsOnUninstall; import static android.service.dreams.Flags.disallowDreamOnAutoProjection; import static android.service.dreams.Flags.dreamHandlesBeingObscured; import static android.service.dreams.Flags.dreamsV2; import static android.service.dreams.Flags.wakeOnStoppingDoze; import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID; Loading Loading @@ -267,29 +268,29 @@ public final class DreamManagerService extends SystemService { } public DreamManagerService(Context context) { this(context, new DreamHandler(FgThread.get().getLooper())); this(new DefaultInjector(context, new DreamHandler(FgThread.get().getLooper()))); } @VisibleForTesting DreamManagerService(Context context, Handler handler) { super(context); mContext = context; mHandler = handler; mController = new DreamController(context, mHandler, mControllerListener); DreamManagerService(Injector injector) { super(injector.getContext()); mContext = injector.getContext(); mHandler = injector.getHandler(); mController = injector.getDreamController(mControllerListener); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mPowerManager = mContext.getSystemService(PowerManager.class); mPowerManagerInternal = getLocalService(PowerManagerInternal.class); mUiModeManager = (UiModeManager) context.getSystemService(Context.UI_MODE_SERVICE); mUiModeManager = mContext.getSystemService(UiModeManager.class); mAtmInternal = getLocalService(ActivityTaskManagerInternal.class); mPmInternal = getLocalService(PackageManagerInternal.class); mUserManager = context.getSystemService(UserManager.class); mUserManager = mContext.getSystemService(UserManager.class); mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, DOZE_WAKE_LOCK_TAG); mDozeConfig = new AmbientDisplayConfiguration(mContext); mDozeConfig = injector.getDozeConfig(); mUiEventLogger = new UiEventLoggerImpl(); mDreamUiEventLogger = new DreamUiEventLoggerImpl( mContext.getResources().getStringArray(R.array.config_loggable_dream_prefixes)); AmbientDisplayConfiguration adc = new AmbientDisplayConfiguration(mContext); mAmbientDisplayComponent = ComponentName.unflattenFromString(adc.ambientDisplayComponent()); mAmbientDisplayComponent = ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent()); mDreamsOnlyEnabledForDockUser = mContext.getResources().getBoolean(R.bool.config_dreamsOnlyEnabledForDockUser); mDismissDreamOnActivityStart = mContext.getResources().getBoolean( Loading Loading @@ -702,7 +703,8 @@ public final class DreamManagerService extends SystemService { } } private void startDreamInternal(boolean doze, String reason) { @VisibleForTesting void startDreamInternal(boolean doze, String reason) { final int userId = ActivityManager.getCurrentUser(); final ComponentName dream = chooseDreamForUser(doze, userId); if (dream != null) { Loading @@ -716,13 +718,15 @@ public final class DreamManagerService extends SystemService { stopDreamInternal(false, "stopping dream from shell"); } private void stopDreamInternal(boolean immediate, String reason) { @VisibleForTesting void stopDreamInternal(boolean immediate, String reason) { synchronized (mLock) { stopDreamLocked(immediate, reason); } } private void startDozingInternal(IBinder token, int screenState, @VisibleForTesting void startDozingInternal(IBinder token, int screenState, @Display.StateReason int reason, float screenBrightness, boolean useNormalBrightnessForDoze) { Slog.d(TAG, "Dream requested to start dozing: " + token Loading Loading @@ -1008,6 +1012,12 @@ public final class DreamManagerService extends SystemService { mCurrentDream.name.flattenToString()); } if (mCurrentDream.isDozing) { if (wakeOnStoppingDoze()) { mPowerManager.wakeUp( SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_DOZE_STOPPED, "android.server.dreams:requestAwaken"); } mDozeWakeLock.release(); } mCurrentDream = null; Loading Loading @@ -1085,6 +1095,48 @@ public final class DreamManagerService extends SystemService { } }; /** * A helper interface to inject dependencies into {@link DreamManagerService}. * @hide */ @VisibleForTesting interface Injector { Context getContext(); Handler getHandler(); AmbientDisplayConfiguration getDozeConfig(); DreamController getDreamController(DreamController.Listener controllerListener); } private static final class DefaultInjector implements Injector { private final Context mContext; private final Handler mHandler; DefaultInjector(Context context, Handler handler) { mContext = context; mHandler = handler; } @Override public Context getContext() { return mContext; } @Override public Handler getHandler() { return mHandler; } @Override public AmbientDisplayConfiguration getDozeConfig() { return new AmbientDisplayConfiguration(mContext); } @Override public DreamController getDreamController(DreamController.Listener controllerListener) { return new DreamController(mContext, mHandler, controllerListener); } } /** * Handler for asynchronous operations performed by the dream manager. * Ensures operations to {@link DreamController} are single-threaded. Loading services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceTest.java +153 −17 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.os.BatteryManager.EXTRA_CHARGING_STATUS; import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT; import static android.service.dreams.Flags.FLAG_DISALLOW_DREAM_ON_AUTO_PROJECTION; import static android.service.dreams.Flags.FLAG_DREAMS_V2; import static android.service.dreams.Flags.FLAG_WAKE_ON_STOPPING_DOZE; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; Loading @@ -29,8 +30,13 @@ import static com.android.server.dreams.DreamManagerService.CHARGE_LIMIT_PERCENT import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; Loading @@ -41,9 +47,16 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.health.BatteryChargingState; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.Binder; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.UserManager; Loading @@ -59,6 +72,7 @@ import com.android.internal.util.test.LocalServiceKeeperRule; import com.android.server.SystemService; import com.android.server.input.InputManagerInternal; import com.android.server.testutils.TestHandler; import com.android.server.wm.ActivityTaskManagerInternal; import org.junit.Before; import org.junit.Rule; Loading @@ -79,19 +93,32 @@ public class DreamManagerServiceTest { private ContextWrapper mContextSpy; @Mock private DreamController mDreamControllerMock; @Mock private ActivityManagerInternal mActivityManagerInternalMock; @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternalMock; @Mock private BatteryManagerInternal mBatteryManagerInternal; @Mock private InputManagerInternal mInputManagerInternal; @Mock private PackageManager mPackageManagerMock; @Mock private PowerManagerInternal mPowerManagerInternalMock; @Mock private PowerManager mPowerManagerMock; @Mock private UiModeManager mUiModeManagerMock; @Mock private UserManager mUserManagerMock; @Mock private PowerManager.WakeLock mWakeLockMock; @Mock private AmbientDisplayConfiguration mDozeConfigMock; @Rule public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule(); Loading @@ -113,6 +140,8 @@ public class DreamManagerServiceTest { mLocalServiceKeeperRule.overrideLocalService(ActivityManagerInternal.class, mActivityManagerInternalMock); mLocalServiceKeeperRule.overrideLocalService(ActivityTaskManagerInternal.class, mActivityTaskManagerInternalMock); mLocalServiceKeeperRule.overrideLocalService(BatteryManagerInternal.class, mBatteryManagerInternal); mLocalServiceKeeperRule.overrideLocalService(InputManagerInternal.class, Loading @@ -127,12 +156,56 @@ public class DreamManagerServiceTest { Settings.Secure.putInt(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_RESTRICT_TO_WIRELESS_CHARGING, 0); when(mPowerManagerMock.newWakeLock(anyInt(), any())).thenReturn(mWakeLockMock); doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt()); when(mContextSpy.getPackageManager()).thenReturn(mPackageManagerMock); when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(mPowerManagerMock); when(mContextSpy.getSystemService(UserManager.class)).thenReturn(mUserManagerMock); when(mContextSpy.getSystemService(Context.UI_MODE_SERVICE)).thenReturn(mUiModeManagerMock); when(mContextSpy.getSystemService(UiModeManager.class)).thenReturn(mUiModeManagerMock); when(mDozeConfigMock.ambientDisplayComponent()) .thenReturn("test.doze.component/.TestDozeService"); } private DreamManagerService createService() { return new DreamManagerService(mContextSpy, mTestHandler); return new DreamManagerService( new TestInjector(mContextSpy, mTestHandler, mDreamControllerMock, mDozeConfigMock)); } /** * Starts dreaming and returns the dream token. */ private Binder startDream(DreamManagerService service) { service.startDreamInternal(/*doze=*/ true, "testing"); ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mWakeLockMock).wrap(runnableCaptor.capture()); runnableCaptor.getValue().run(); ArgumentCaptor<Binder> dreamTokenCaptor = ArgumentCaptor.forClass(Binder.class); verify(mDreamControllerMock) .startDream( dreamTokenCaptor.capture(), any(), anyBoolean(), anyBoolean(), anyInt(), any(), any(), any()); return dreamTokenCaptor.getValue(); } /** * Trigger battery change event so charging state is read. */ private void sendBatteryChangeEvent() { ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContextSpy, new Intent()); } @Test Loading Loading @@ -176,11 +249,7 @@ public class DreamManagerServiceTest { service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContext, new Intent()); sendBatteryChangeEvent(); // Can start dreaming is true. assertThat(service.canStartDreamingInternal(/*isScreenOn=*/ true)).isTrue(); Loading @@ -207,16 +276,52 @@ public class DreamManagerServiceTest { service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContext, new Intent()); sendBatteryChangeEvent(); // Can start dreaming is true. assertThat(service.canStartDreamingInternal(/*isScreenOn=*/ true)).isFalse(); } @EnableFlags(FLAG_WAKE_ON_STOPPING_DOZE) @Test public void testStopDream_sendsWakeIfDozing() throws PackageManager.NameNotFoundException { // Enable dreaming while charging only. Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_ENABLED, 1, UserHandle.USER_CURRENT); Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, UserHandle.USER_CURRENT); // Set up preconditions. ServiceInfo dozeServiceInfo = new ServiceInfo(); dozeServiceInfo.applicationInfo = new ApplicationInfo(); when(mUserManagerMock.isUserUnlocked()).thenReturn(true); when(mDozeConfigMock.enabled(anyInt())).thenReturn(true); when(mPackageManagerMock.getServiceInfo(any(), anyInt())).thenReturn(dozeServiceInfo); // Device is charging. when(mBatteryManagerInternal.isPowered(anyInt())).thenReturn(true); // Initialize service so settings are read. final DreamManagerService service = createService(); service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. sendBatteryChangeEvent(); // Start dream. final Binder dreamToken = startDream(service); // Start dozing. service.startDozingInternal(dreamToken, 0, 0, 0f, false); // Stop dreaming. service.stopDreamInternal(true, "testing"); // wakeUp is sent. verify(mPowerManagerMock) .wakeUp(anyLong(), eq(PowerManager.WAKE_REASON_DOZE_STOPPED), any()); } @Test public void testDreamConditionActive_onDock() { // Enable dreaming on dock. Loading Loading @@ -277,11 +382,7 @@ public class DreamManagerServiceTest { service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContext, new Intent()); sendBatteryChangeEvent(); // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); Loading Loading @@ -361,4 +462,39 @@ public class DreamManagerServiceTest { // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); } private static final class TestInjector implements DreamManagerService.Injector { private final Context mContext; private final Handler mHandler; private final DreamController mDreamController; private final AmbientDisplayConfiguration mDozeConfig; TestInjector(Context context, Handler handler, DreamController dreamController, AmbientDisplayConfiguration dozeConfig) { mContext = context; mHandler = handler; mDreamController = dreamController; mDozeConfig = dozeConfig; } @Override public Context getContext() { return mContext; } @Override public Handler getHandler() { return mHandler; } @Override public AmbientDisplayConfiguration getDozeConfig() { return mDozeConfig; } @Override public DreamController getDreamController(DreamController.Listener controllerListener) { return mDreamController; } } } Loading
core/java/android/os/PowerManager.java +9 −0 Original line number Diff line number Diff line Loading @@ -687,6 +687,7 @@ public final class PowerManager { WAKE_REASON_LIFT, WAKE_REASON_BIOMETRIC, WAKE_REASON_DOCK, WAKE_REASON_DOZE_STOPPED, }) @Retention(RetentionPolicy.SOURCE) public @interface WakeReason{} Loading Loading @@ -833,6 +834,13 @@ public final class PowerManager { */ public static final int WAKE_REASON_DOCK = 18; /** * Wake up reason code: Waking the dream because the dozing was stopped directly through dream * APIs rather than some other more specific reason. * @hide */ public static final int WAKE_REASON_DOZE_STOPPED = 19; /** * Convert the wake reason to a string for debugging purposes. * @hide Loading @@ -858,6 +866,7 @@ public final class PowerManager { case WAKE_REASON_LIFT: return "WAKE_REASON_LIFT"; case WAKE_REASON_BIOMETRIC: return "WAKE_REASON_BIOMETRIC"; case WAKE_REASON_DOCK: return "WAKE_REASON_DOCK"; case WAKE_REASON_DOZE_STOPPED: return "WAKE_REASON_DOZE_STOPPED"; default: return Integer.toString(wakeReason); } } Loading
core/java/android/service/dreams/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -140,3 +140,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "wake_on_stopping_doze" namespace: "systemui" description: "Sends a wakeUp when explicitly stopping the doze dream" bug: "298073718" metadata { purpose: PURPOSE_BUGFIX } }
services/core/java/com/android/server/dreams/DreamManagerService.java +67 −15 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.service.dreams.Flags.cleanupDreamSettingsOnUninstall; import static android.service.dreams.Flags.disallowDreamOnAutoProjection; import static android.service.dreams.Flags.dreamHandlesBeingObscured; import static android.service.dreams.Flags.dreamsV2; import static android.service.dreams.Flags.wakeOnStoppingDoze; import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID; Loading Loading @@ -267,29 +268,29 @@ public final class DreamManagerService extends SystemService { } public DreamManagerService(Context context) { this(context, new DreamHandler(FgThread.get().getLooper())); this(new DefaultInjector(context, new DreamHandler(FgThread.get().getLooper()))); } @VisibleForTesting DreamManagerService(Context context, Handler handler) { super(context); mContext = context; mHandler = handler; mController = new DreamController(context, mHandler, mControllerListener); DreamManagerService(Injector injector) { super(injector.getContext()); mContext = injector.getContext(); mHandler = injector.getHandler(); mController = injector.getDreamController(mControllerListener); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mPowerManager = mContext.getSystemService(PowerManager.class); mPowerManagerInternal = getLocalService(PowerManagerInternal.class); mUiModeManager = (UiModeManager) context.getSystemService(Context.UI_MODE_SERVICE); mUiModeManager = mContext.getSystemService(UiModeManager.class); mAtmInternal = getLocalService(ActivityTaskManagerInternal.class); mPmInternal = getLocalService(PackageManagerInternal.class); mUserManager = context.getSystemService(UserManager.class); mUserManager = mContext.getSystemService(UserManager.class); mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, DOZE_WAKE_LOCK_TAG); mDozeConfig = new AmbientDisplayConfiguration(mContext); mDozeConfig = injector.getDozeConfig(); mUiEventLogger = new UiEventLoggerImpl(); mDreamUiEventLogger = new DreamUiEventLoggerImpl( mContext.getResources().getStringArray(R.array.config_loggable_dream_prefixes)); AmbientDisplayConfiguration adc = new AmbientDisplayConfiguration(mContext); mAmbientDisplayComponent = ComponentName.unflattenFromString(adc.ambientDisplayComponent()); mAmbientDisplayComponent = ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent()); mDreamsOnlyEnabledForDockUser = mContext.getResources().getBoolean(R.bool.config_dreamsOnlyEnabledForDockUser); mDismissDreamOnActivityStart = mContext.getResources().getBoolean( Loading Loading @@ -702,7 +703,8 @@ public final class DreamManagerService extends SystemService { } } private void startDreamInternal(boolean doze, String reason) { @VisibleForTesting void startDreamInternal(boolean doze, String reason) { final int userId = ActivityManager.getCurrentUser(); final ComponentName dream = chooseDreamForUser(doze, userId); if (dream != null) { Loading @@ -716,13 +718,15 @@ public final class DreamManagerService extends SystemService { stopDreamInternal(false, "stopping dream from shell"); } private void stopDreamInternal(boolean immediate, String reason) { @VisibleForTesting void stopDreamInternal(boolean immediate, String reason) { synchronized (mLock) { stopDreamLocked(immediate, reason); } } private void startDozingInternal(IBinder token, int screenState, @VisibleForTesting void startDozingInternal(IBinder token, int screenState, @Display.StateReason int reason, float screenBrightness, boolean useNormalBrightnessForDoze) { Slog.d(TAG, "Dream requested to start dozing: " + token Loading Loading @@ -1008,6 +1012,12 @@ public final class DreamManagerService extends SystemService { mCurrentDream.name.flattenToString()); } if (mCurrentDream.isDozing) { if (wakeOnStoppingDoze()) { mPowerManager.wakeUp( SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_DOZE_STOPPED, "android.server.dreams:requestAwaken"); } mDozeWakeLock.release(); } mCurrentDream = null; Loading Loading @@ -1085,6 +1095,48 @@ public final class DreamManagerService extends SystemService { } }; /** * A helper interface to inject dependencies into {@link DreamManagerService}. * @hide */ @VisibleForTesting interface Injector { Context getContext(); Handler getHandler(); AmbientDisplayConfiguration getDozeConfig(); DreamController getDreamController(DreamController.Listener controllerListener); } private static final class DefaultInjector implements Injector { private final Context mContext; private final Handler mHandler; DefaultInjector(Context context, Handler handler) { mContext = context; mHandler = handler; } @Override public Context getContext() { return mContext; } @Override public Handler getHandler() { return mHandler; } @Override public AmbientDisplayConfiguration getDozeConfig() { return new AmbientDisplayConfiguration(mContext); } @Override public DreamController getDreamController(DreamController.Listener controllerListener) { return new DreamController(mContext, mHandler, controllerListener); } } /** * Handler for asynchronous operations performed by the dream manager. * Ensures operations to {@link DreamController} are single-threaded. Loading
services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceTest.java +153 −17 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.os.BatteryManager.EXTRA_CHARGING_STATUS; import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT; import static android.service.dreams.Flags.FLAG_DISALLOW_DREAM_ON_AUTO_PROJECTION; import static android.service.dreams.Flags.FLAG_DREAMS_V2; import static android.service.dreams.Flags.FLAG_WAKE_ON_STOPPING_DOZE; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; Loading @@ -29,8 +30,13 @@ import static com.android.server.dreams.DreamManagerService.CHARGE_LIMIT_PERCENT import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; Loading @@ -41,9 +47,16 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.health.BatteryChargingState; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.Binder; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.UserManager; Loading @@ -59,6 +72,7 @@ import com.android.internal.util.test.LocalServiceKeeperRule; import com.android.server.SystemService; import com.android.server.input.InputManagerInternal; import com.android.server.testutils.TestHandler; import com.android.server.wm.ActivityTaskManagerInternal; import org.junit.Before; import org.junit.Rule; Loading @@ -79,19 +93,32 @@ public class DreamManagerServiceTest { private ContextWrapper mContextSpy; @Mock private DreamController mDreamControllerMock; @Mock private ActivityManagerInternal mActivityManagerInternalMock; @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternalMock; @Mock private BatteryManagerInternal mBatteryManagerInternal; @Mock private InputManagerInternal mInputManagerInternal; @Mock private PackageManager mPackageManagerMock; @Mock private PowerManagerInternal mPowerManagerInternalMock; @Mock private PowerManager mPowerManagerMock; @Mock private UiModeManager mUiModeManagerMock; @Mock private UserManager mUserManagerMock; @Mock private PowerManager.WakeLock mWakeLockMock; @Mock private AmbientDisplayConfiguration mDozeConfigMock; @Rule public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule(); Loading @@ -113,6 +140,8 @@ public class DreamManagerServiceTest { mLocalServiceKeeperRule.overrideLocalService(ActivityManagerInternal.class, mActivityManagerInternalMock); mLocalServiceKeeperRule.overrideLocalService(ActivityTaskManagerInternal.class, mActivityTaskManagerInternalMock); mLocalServiceKeeperRule.overrideLocalService(BatteryManagerInternal.class, mBatteryManagerInternal); mLocalServiceKeeperRule.overrideLocalService(InputManagerInternal.class, Loading @@ -127,12 +156,56 @@ public class DreamManagerServiceTest { Settings.Secure.putInt(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_RESTRICT_TO_WIRELESS_CHARGING, 0); when(mPowerManagerMock.newWakeLock(anyInt(), any())).thenReturn(mWakeLockMock); doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt()); when(mContextSpy.getPackageManager()).thenReturn(mPackageManagerMock); when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(mPowerManagerMock); when(mContextSpy.getSystemService(UserManager.class)).thenReturn(mUserManagerMock); when(mContextSpy.getSystemService(Context.UI_MODE_SERVICE)).thenReturn(mUiModeManagerMock); when(mContextSpy.getSystemService(UiModeManager.class)).thenReturn(mUiModeManagerMock); when(mDozeConfigMock.ambientDisplayComponent()) .thenReturn("test.doze.component/.TestDozeService"); } private DreamManagerService createService() { return new DreamManagerService(mContextSpy, mTestHandler); return new DreamManagerService( new TestInjector(mContextSpy, mTestHandler, mDreamControllerMock, mDozeConfigMock)); } /** * Starts dreaming and returns the dream token. */ private Binder startDream(DreamManagerService service) { service.startDreamInternal(/*doze=*/ true, "testing"); ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mWakeLockMock).wrap(runnableCaptor.capture()); runnableCaptor.getValue().run(); ArgumentCaptor<Binder> dreamTokenCaptor = ArgumentCaptor.forClass(Binder.class); verify(mDreamControllerMock) .startDream( dreamTokenCaptor.capture(), any(), anyBoolean(), anyBoolean(), anyInt(), any(), any(), any()); return dreamTokenCaptor.getValue(); } /** * Trigger battery change event so charging state is read. */ private void sendBatteryChangeEvent() { ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContextSpy, new Intent()); } @Test Loading Loading @@ -176,11 +249,7 @@ public class DreamManagerServiceTest { service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContext, new Intent()); sendBatteryChangeEvent(); // Can start dreaming is true. assertThat(service.canStartDreamingInternal(/*isScreenOn=*/ true)).isTrue(); Loading @@ -207,16 +276,52 @@ public class DreamManagerServiceTest { service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContext, new Intent()); sendBatteryChangeEvent(); // Can start dreaming is true. assertThat(service.canStartDreamingInternal(/*isScreenOn=*/ true)).isFalse(); } @EnableFlags(FLAG_WAKE_ON_STOPPING_DOZE) @Test public void testStopDream_sendsWakeIfDozing() throws PackageManager.NameNotFoundException { // Enable dreaming while charging only. Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_ENABLED, 1, UserHandle.USER_CURRENT); Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, UserHandle.USER_CURRENT); // Set up preconditions. ServiceInfo dozeServiceInfo = new ServiceInfo(); dozeServiceInfo.applicationInfo = new ApplicationInfo(); when(mUserManagerMock.isUserUnlocked()).thenReturn(true); when(mDozeConfigMock.enabled(anyInt())).thenReturn(true); when(mPackageManagerMock.getServiceInfo(any(), anyInt())).thenReturn(dozeServiceInfo); // Device is charging. when(mBatteryManagerInternal.isPowered(anyInt())).thenReturn(true); // Initialize service so settings are read. final DreamManagerService service = createService(); service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. sendBatteryChangeEvent(); // Start dream. final Binder dreamToken = startDream(service); // Start dozing. service.startDozingInternal(dreamToken, 0, 0, 0f, false); // Stop dreaming. service.stopDreamInternal(true, "testing"); // wakeUp is sent. verify(mPowerManagerMock) .wakeUp(anyLong(), eq(PowerManager.WAKE_REASON_DOZE_STOPPED), any()); } @Test public void testDreamConditionActive_onDock() { // Enable dreaming on dock. Loading Loading @@ -277,11 +382,7 @@ public class DreamManagerServiceTest { service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // Battery changed event is received. ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); verify(mContextSpy).registerReceiver(receiverCaptor.capture(), argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED))); receiverCaptor.getValue().onReceive(mContext, new Intent()); sendBatteryChangeEvent(); // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); Loading Loading @@ -361,4 +462,39 @@ public class DreamManagerServiceTest { // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); } private static final class TestInjector implements DreamManagerService.Injector { private final Context mContext; private final Handler mHandler; private final DreamController mDreamController; private final AmbientDisplayConfiguration mDozeConfig; TestInjector(Context context, Handler handler, DreamController dreamController, AmbientDisplayConfiguration dozeConfig) { mContext = context; mHandler = handler; mDreamController = dreamController; mDozeConfig = dozeConfig; } @Override public Context getContext() { return mContext; } @Override public Handler getHandler() { return mHandler; } @Override public AmbientDisplayConfiguration getDozeConfig() { return mDozeConfig; } @Override public DreamController getDreamController(DreamController.Listener controllerListener) { return mDreamController; } } }