Loading core/java/android/service/dreams/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -100,3 +100,13 @@ flag { bug: "403579494" is_fixed_read_only: true } flag { name: "allow_dream_with_charge_limit" namespace: "systemui" description: "Allows dreaming even when a charge limit is active" bug: "397717022" metadata { purpose: PURPOSE_BUGFIX } } No newline at end of file services/core/java/com/android/server/dreams/DreamManagerService.java +61 −14 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import static android.Manifest.permission.BIND_DREAM_SERVICE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.os.BatteryManager.EXTRA_CHARGING_STATUS; import static android.service.dreams.Flags.allowDreamWhenPostured; import static android.service.dreams.Flags.allowDreamWithChargeLimit; import static android.service.dreams.Flags.cleanupDreamSettingsOnUninstall; import static android.service.dreams.Flags.dreamHandlesBeingObscured; import static android.service.dreams.Flags.dreamsV2; Loading @@ -46,6 +48,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ServiceInfo; import android.database.ContentObserver; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.health.BatteryChargingState; import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryManagerInternal; Loading Loading @@ -120,6 +123,13 @@ public final class DreamManagerService extends SystemService { private static final int DREAM_ON_CHARGE = 1 << 1; private static final int DREAM_ON_POSTURED = 1 << 2; /** * Battery percentage at which the device stops charging when the charge limit feature is * enabled. */ @VisibleForTesting static final int CHARGE_LIMIT_PERCENTAGE = 80; private final Object mLock = new Object(); private final Context mContext; Loading Loading @@ -206,13 +216,20 @@ public final class DreamManagerService extends SystemService { } }; private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() { /** * Receiver for the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. */ private final BroadcastReceiver mBatteryChangedReceived = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent batteryChangedIntent) { if (allowDreamWithChargeLimit()) { updateChargingStatus(batteryChangedIntent); } else { mIsCharging = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); mIsWirelessCharging = mBatteryManagerInternal.isPowered( BatteryManager.BATTERY_PLUGGED_WIRELESS); } } }; private final BroadcastReceiver mDockStateReceiver = new BroadcastReceiver() { Loading Loading @@ -320,10 +337,11 @@ public final class DreamManagerService extends SystemService { mContext.registerReceiver( mDockStateReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); IntentFilter chargingIntentFilter = new IntentFilter(); chargingIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); chargingIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mChargingReceiver, chargingIntentFilter); // Broadcast is sticky so we don't need to query state directly. IntentFilter batteryChangedIntentFilter = new IntentFilter(); batteryChangedIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); batteryChangedIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mBatteryChangedReceived, batteryChangedIntentFilter); mSettingsObserver = new SettingsObserver(mHandler); mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( Loading @@ -342,11 +360,13 @@ public final class DreamManagerService extends SystemService { Settings.Secure.SCREENSAVER_RESTRICT_TO_WIRELESS_CHARGING), false, mSettingsObserver, UserHandle.USER_ALL); if (!allowDreamWithChargeLimit()) { // We don't get an initial broadcast for the battery state, so we have to initialize // directly from BatteryManager. mIsCharging = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); mIsWirelessCharging = mBatteryManagerInternal.isPowered( BatteryManager.BATTERY_PLUGGED_WIRELESS); } updateWhenToDreamSettings(); } Loading Loading @@ -424,6 +444,33 @@ public final class DreamManagerService extends SystemService { } } private void updateChargingStatus(Intent batteryChangedIntent) { mIsWirelessCharging = mBatteryManagerInternal.isPowered( BatteryManager.BATTERY_PLUGGED_WIRELESS); if (mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY)) { mIsCharging = true; } else { // When charge limit is enabled and the device is at the charge limit battery %, the // device stops charging entirely and the plug type is reported as BATTERY_PLUGGED_NONE. // Check if the feature is enabled so that the device can still dream when charge limit // is active. final ContentResolver resolver = mContext.getContentResolver(); final boolean isChargeLimitEnabled = Settings.Secure.getIntForUser(resolver, Settings.Secure.CHARGE_OPTIMIZATION_MODE, /*default=*/ 0, UserHandle.USER_CURRENT) != 0; int chargingStatus = batteryChangedIntent.getIntExtra(EXTRA_CHARGING_STATUS, BatteryChargingState.NORMAL); final boolean isChargeLimitActive = mBatteryManagerInternal.getBatteryLevel() >= CHARGE_LIMIT_PERCENTAGE && chargingStatus == BatteryChargingState.LONG_LIFE; mIsCharging = isChargeLimitEnabled && isChargeLimitActive; } } private void updateWhenToDreamSettings() { synchronized (mLock) { final ContentResolver resolver = mContext.getContentResolver(); Loading services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceTest.java +42 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,14 @@ package com.android.server.dreams; import static android.os.BatteryManager.EXTRA_CHARGING_STATUS; import static android.service.dreams.Flags.FLAG_DREAMS_V2; import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.dreams.DreamManagerService.CHARGE_LIMIT_PERCENTAGE; import static com.google.common.truth.Truth.assertThat; Loading @@ -33,6 +36,7 @@ import android.app.ActivityManagerInternal; import android.content.BroadcastReceiver; import android.content.ContextWrapper; import android.content.Intent; import android.hardware.health.BatteryChargingState; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.PowerManagerInternal; Loading Loading @@ -200,6 +204,44 @@ public class DreamManagerServiceTest { final DreamManagerService service = createService(); 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()); // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); } @EnableFlags(FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT) @Test public void testDreamConditionActive_chargeLimitActive() { // Enable dreaming while charging only. Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, UserHandle.USER_CURRENT); // Enable charge limit setting. Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.CHARGE_OPTIMIZATION_MODE, 1, UserHandle.USER_CURRENT); // Device is not considered charging when charge limit is on. when(mBatteryManagerInternal.isPowered(anyInt())).thenReturn(false); when(mBatteryManagerInternal.getBatteryLevel()).thenReturn(CHARGE_LIMIT_PERCENTAGE); // Initialize service so settings are read. final DreamManagerService service = createService(); 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))); Intent intent = new Intent(); intent.putExtra(EXTRA_CHARGING_STATUS, BatteryChargingState.LONG_LIFE); receiverCaptor.getValue().onReceive(mContext, intent); // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); } Loading Loading
core/java/android/service/dreams/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -100,3 +100,13 @@ flag { bug: "403579494" is_fixed_read_only: true } flag { name: "allow_dream_with_charge_limit" namespace: "systemui" description: "Allows dreaming even when a charge limit is active" bug: "397717022" metadata { purpose: PURPOSE_BUGFIX } } No newline at end of file
services/core/java/com/android/server/dreams/DreamManagerService.java +61 −14 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import static android.Manifest.permission.BIND_DREAM_SERVICE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.os.BatteryManager.EXTRA_CHARGING_STATUS; import static android.service.dreams.Flags.allowDreamWhenPostured; import static android.service.dreams.Flags.allowDreamWithChargeLimit; import static android.service.dreams.Flags.cleanupDreamSettingsOnUninstall; import static android.service.dreams.Flags.dreamHandlesBeingObscured; import static android.service.dreams.Flags.dreamsV2; Loading @@ -46,6 +48,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ServiceInfo; import android.database.ContentObserver; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.health.BatteryChargingState; import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryManagerInternal; Loading Loading @@ -120,6 +123,13 @@ public final class DreamManagerService extends SystemService { private static final int DREAM_ON_CHARGE = 1 << 1; private static final int DREAM_ON_POSTURED = 1 << 2; /** * Battery percentage at which the device stops charging when the charge limit feature is * enabled. */ @VisibleForTesting static final int CHARGE_LIMIT_PERCENTAGE = 80; private final Object mLock = new Object(); private final Context mContext; Loading Loading @@ -206,13 +216,20 @@ public final class DreamManagerService extends SystemService { } }; private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() { /** * Receiver for the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. */ private final BroadcastReceiver mBatteryChangedReceived = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent batteryChangedIntent) { if (allowDreamWithChargeLimit()) { updateChargingStatus(batteryChangedIntent); } else { mIsCharging = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); mIsWirelessCharging = mBatteryManagerInternal.isPowered( BatteryManager.BATTERY_PLUGGED_WIRELESS); } } }; private final BroadcastReceiver mDockStateReceiver = new BroadcastReceiver() { Loading Loading @@ -320,10 +337,11 @@ public final class DreamManagerService extends SystemService { mContext.registerReceiver( mDockStateReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); IntentFilter chargingIntentFilter = new IntentFilter(); chargingIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); chargingIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mChargingReceiver, chargingIntentFilter); // Broadcast is sticky so we don't need to query state directly. IntentFilter batteryChangedIntentFilter = new IntentFilter(); batteryChangedIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); batteryChangedIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mBatteryChangedReceived, batteryChangedIntentFilter); mSettingsObserver = new SettingsObserver(mHandler); mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( Loading @@ -342,11 +360,13 @@ public final class DreamManagerService extends SystemService { Settings.Secure.SCREENSAVER_RESTRICT_TO_WIRELESS_CHARGING), false, mSettingsObserver, UserHandle.USER_ALL); if (!allowDreamWithChargeLimit()) { // We don't get an initial broadcast for the battery state, so we have to initialize // directly from BatteryManager. mIsCharging = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); mIsWirelessCharging = mBatteryManagerInternal.isPowered( BatteryManager.BATTERY_PLUGGED_WIRELESS); } updateWhenToDreamSettings(); } Loading Loading @@ -424,6 +444,33 @@ public final class DreamManagerService extends SystemService { } } private void updateChargingStatus(Intent batteryChangedIntent) { mIsWirelessCharging = mBatteryManagerInternal.isPowered( BatteryManager.BATTERY_PLUGGED_WIRELESS); if (mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY)) { mIsCharging = true; } else { // When charge limit is enabled and the device is at the charge limit battery %, the // device stops charging entirely and the plug type is reported as BATTERY_PLUGGED_NONE. // Check if the feature is enabled so that the device can still dream when charge limit // is active. final ContentResolver resolver = mContext.getContentResolver(); final boolean isChargeLimitEnabled = Settings.Secure.getIntForUser(resolver, Settings.Secure.CHARGE_OPTIMIZATION_MODE, /*default=*/ 0, UserHandle.USER_CURRENT) != 0; int chargingStatus = batteryChangedIntent.getIntExtra(EXTRA_CHARGING_STATUS, BatteryChargingState.NORMAL); final boolean isChargeLimitActive = mBatteryManagerInternal.getBatteryLevel() >= CHARGE_LIMIT_PERCENTAGE && chargingStatus == BatteryChargingState.LONG_LIFE; mIsCharging = isChargeLimitEnabled && isChargeLimitActive; } } private void updateWhenToDreamSettings() { synchronized (mLock) { final ContentResolver resolver = mContext.getContentResolver(); Loading
services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceTest.java +42 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,14 @@ package com.android.server.dreams; import static android.os.BatteryManager.EXTRA_CHARGING_STATUS; import static android.service.dreams.Flags.FLAG_DREAMS_V2; import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.dreams.DreamManagerService.CHARGE_LIMIT_PERCENTAGE; import static com.google.common.truth.Truth.assertThat; Loading @@ -33,6 +36,7 @@ import android.app.ActivityManagerInternal; import android.content.BroadcastReceiver; import android.content.ContextWrapper; import android.content.Intent; import android.hardware.health.BatteryChargingState; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.PowerManagerInternal; Loading Loading @@ -200,6 +204,44 @@ public class DreamManagerServiceTest { final DreamManagerService service = createService(); 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()); // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); } @EnableFlags(FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT) @Test public void testDreamConditionActive_chargeLimitActive() { // Enable dreaming while charging only. Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, UserHandle.USER_CURRENT); // Enable charge limit setting. Settings.Secure.putIntForUser(mContextSpy.getContentResolver(), Settings.Secure.CHARGE_OPTIMIZATION_MODE, 1, UserHandle.USER_CURRENT); // Device is not considered charging when charge limit is on. when(mBatteryManagerInternal.isPowered(anyInt())).thenReturn(false); when(mBatteryManagerInternal.getBatteryLevel()).thenReturn(CHARGE_LIMIT_PERCENTAGE); // Initialize service so settings are read. final DreamManagerService service = createService(); 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))); Intent intent = new Intent(); intent.putExtra(EXTRA_CHARGING_STATUS, BatteryChargingState.LONG_LIFE); receiverCaptor.getValue().onReceive(mContext, intent); // Dream condition is active. assertThat(service.dreamConditionActiveInternal()).isTrue(); } Loading