diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 3495f9520abc3..48b932649e740 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7854,6 +7854,7 @@ package android.os { public static final class BatterySaverPolicyConfig.Builder { ctor public BatterySaverPolicyConfig.Builder(); + ctor public BatterySaverPolicyConfig.Builder(@NonNull android.os.BatterySaverPolicyConfig); method @NonNull public android.os.BatterySaverPolicyConfig.Builder addDeviceSpecificSetting(@NonNull String, @NonNull String); method @NonNull public android.os.BatterySaverPolicyConfig build(); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setAdjustBrightnessFactor(float); @@ -8221,6 +8222,7 @@ package android.os { public final class PowerManager { method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long); method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend(); + method @NonNull public android.os.BatterySaverPolicyConfig getFullPowerSavePolicy(); method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveModeTrigger(); method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplayAvailable(); method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressed(); @@ -8229,6 +8231,7 @@ package android.os { method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig); method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean); method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int); + method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setFullPowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig); method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean); method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int); diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java index 6f5139038e866..81c781bff06d6 100644 --- a/core/java/android/os/BatterySaverPolicyConfig.java +++ b/core/java/android/os/BatterySaverPolicyConfig.java @@ -340,6 +340,38 @@ public final class BatterySaverPolicyConfig implements Parcelable { public Builder() { } + /** + * Creates a Builder prepopulated with the values from the passed in + * {@link BatterySaverPolicyConfig}. + */ + public Builder(@NonNull BatterySaverPolicyConfig batterySaverPolicyConfig) { + mAdjustBrightnessFactor = batterySaverPolicyConfig.getAdjustBrightnessFactor(); + mAdvertiseIsEnabled = batterySaverPolicyConfig.getAdvertiseIsEnabled(); + mDeferFullBackup = batterySaverPolicyConfig.getDeferFullBackup(); + mDeferKeyValueBackup = batterySaverPolicyConfig.getDeferKeyValueBackup(); + + for (String key : + batterySaverPolicyConfig.getDeviceSpecificSettings().keySet()) { + mDeviceSpecificSettings.put(key, + batterySaverPolicyConfig.getDeviceSpecificSettings().get(key)); + } + + mDisableAnimation = batterySaverPolicyConfig.getDisableAnimation(); + mDisableAod = batterySaverPolicyConfig.getDisableAod(); + mDisableLaunchBoost = batterySaverPolicyConfig.getDisableLaunchBoost(); + mDisableOptionalSensors = batterySaverPolicyConfig.getDisableOptionalSensors(); + mDisableVibration = batterySaverPolicyConfig.getDisableVibration(); + mEnableAdjustBrightness = batterySaverPolicyConfig.getEnableAdjustBrightness(); + mEnableDataSaver = batterySaverPolicyConfig.getEnableDataSaver(); + mEnableFirewall = batterySaverPolicyConfig.getEnableFirewall(); + mEnableNightMode = batterySaverPolicyConfig.getEnableNightMode(); + mEnableQuickDoze = batterySaverPolicyConfig.getEnableQuickDoze(); + mForceAllAppsStandby = batterySaverPolicyConfig.getForceAllAppsStandby(); + mForceBackgroundCheck = batterySaverPolicyConfig.getForceBackgroundCheck(); + mLocationMode = batterySaverPolicyConfig.getLocationMode(); + mSoundTriggerMode = batterySaverPolicyConfig.getSoundTriggerMode(); + } + /** * Set how much to adjust the screen brightness while in Battery Saver. The value should * be in the [0, 1] range, where 1 will not change the brightness. This will have no diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 90cbac50b3913..8f6161329e533 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -55,6 +55,8 @@ interface IPowerManager boolean isPowerSaveMode(); PowerSaveState getPowerSaveState(int serviceType); boolean setPowerSaveModeEnabled(boolean mode); + BatterySaverPolicyConfig getFullPowerSavePolicy(); + boolean setFullPowerSavePolicy(in BatterySaverPolicyConfig config); boolean setDynamicPowerSaveHint(boolean powerSaveHint, int disableThreshold); boolean setAdaptivePowerSavePolicy(in BatterySaverPolicyConfig config); boolean setAdaptivePowerSaveEnabled(boolean enabled); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 90648325ae0ea..9a102a7c4b009 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1637,6 +1637,65 @@ public final class PowerManager { } } + /** + * Gets the current policy for full power save mode. + * + * @return The {@link BatterySaverPolicyConfig} which is currently set for the full power save + * policy level. + * + * @hide + */ + @SystemApi + @NonNull + public BatterySaverPolicyConfig getFullPowerSavePolicy() { + try { + return mService.getFullPowerSavePolicy(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets the policy for full power save mode. + * + * Any settings set by this API will persist for only one session of full battery saver mode. + * The settings set by this API are cleared upon exit of full battery saver mode, and the + * caller is expected to set the desired values again for the next full battery saver mode + * session if desired. + * + * Use-cases: + * 1. Set policy outside of full battery saver mode + * - full policy set -> enter BS -> policy setting applied -> exit BS -> setting cleared + * 2. Set policy inside of full battery saver mode + * - enter BS -> full policy set -> policy setting applied -> exit BS -> setting cleared + * + * This API is intended to be used with {@link #getFullPowerSavePolicy()} API when a client only + * wants to modify a specific setting(s) and leave the remaining policy attributes the same. + * Example: + * BatterySaverPolicyConfig newFullPolicyConfig = + * new BatterySaverPolicyConfig.Builder(powerManager.getFullPowerSavePolicy()) + * .setSoundTriggerMode(PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED) + * .build(); + * powerManager.setFullPowerSavePolicy(newFullPolicyConfig); + * + * @return true if there was an effectual change. If full battery saver is enabled, then this + * will return true. + * + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.DEVICE_POWER, + android.Manifest.permission.POWER_SAVER + }) + public boolean setFullPowerSavePolicy(@NonNull BatterySaverPolicyConfig config) { + try { + return mService.setFullPowerSavePolicy(config); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Updates the current state of dynamic power savings and disable threshold. This is * a signal to the system which an app can update to serve as an indicator that diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 084dc32e8ad77..54d05124c114c 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -5031,6 +5031,31 @@ public final class PowerManagerService extends SystemService } } + @Override // Binder call + public BatterySaverPolicyConfig getFullPowerSavePolicy() { + final long ident = Binder.clearCallingIdentity(); + try { + return mBatterySaverStateMachine.getFullBatterySaverPolicy(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public boolean setFullPowerSavePolicy(@NonNull BatterySaverPolicyConfig config) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER) + != PackageManager.PERMISSION_GRANTED) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, "setFullPowerSavePolicy"); + } + final long ident = Binder.clearCallingIdentity(); + try { + return mBatterySaverStateMachine.setFullBatterySaverPolicy(config); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + @Override // Binder call public boolean setDynamicPowerSaveHint(boolean powerSaveHint, int disableThreshold) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER, diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index 16f50694ebb96..770779d16102e 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -46,6 +46,7 @@ import com.android.server.LocalServices; import com.android.server.power.PowerManagerService; import com.android.server.power.batterysaver.BatterySaverPolicy.BatterySaverPolicyListener; import com.android.server.power.batterysaver.BatterySaverPolicy.Policy; +import com.android.server.power.batterysaver.BatterySaverPolicy.PolicyLevel; import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState; import com.android.server.power.batterysaver.BatterySavingStats.DozeState; import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState; @@ -133,6 +134,7 @@ public class BatterySaverController implements BatterySaverPolicyListener { public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10; public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11; public static final int REASON_TIMEOUT = 12; + public static final int REASON_FULL_POWER_SAVINGS_CHANGED = 13; static String reasonToString(int reason) { switch (reason) { @@ -162,6 +164,8 @@ public class BatterySaverController implements BatterySaverPolicyListener { return "Adaptive Power Savings changed"; case BatterySaverController.REASON_TIMEOUT: return "timeout"; + case BatterySaverController.REASON_FULL_POWER_SAVINGS_CHANGED: + return "Full Power Savings changed"; default: return "Unknown reason: " + reason; } @@ -313,6 +317,10 @@ public class BatterySaverController implements BatterySaverPolicyListener { } } + BatterySaverPolicyConfig getPolicyLocked(@PolicyLevel int policyLevel) { + return mBatterySaverPolicy.getPolicyLocked(policyLevel).toConfig(); + } + /** * @return whether battery saver is enabled or not. This takes into * account whether a policy says to advertise isEnabled so this can be propagated externally. @@ -340,6 +348,18 @@ public class BatterySaverController implements BatterySaverPolicyListener { } } + boolean setFullPolicyLocked(BatterySaverPolicyConfig config, int reason) { + return setFullPolicyLocked(BatterySaverPolicy.Policy.fromConfig(config), reason); + } + + boolean setFullPolicyLocked(Policy policy, int reason) { + if (mBatterySaverPolicy.setFullPolicyLocked(policy)) { + mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); + return true; + } + return false; + } + boolean isAdaptiveEnabled() { synchronized (mLock) { return getAdaptiveEnabledLocked(); diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java index 98b75df9d4670..03584b9813513 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java @@ -222,6 +222,10 @@ public class BatterySaverPolicy extends ContentObserver implements @GuardedBy("mLock") private Policy mAdaptivePolicy = DEFAULT_ADAPTIVE_POLICY; + /** The current default full policy. */ + @GuardedBy("mLock") + private Policy mDefaultFullPolicy = DEFAULT_FULL_POLICY; + /** The policy to be used for full battery saver. */ @GuardedBy("mLock") private Policy mFullPolicy = DEFAULT_FULL_POLICY; @@ -377,9 +381,8 @@ public class BatterySaverPolicy extends ContentObserver implements } } - if (newFullPolicy != null && !mFullPolicy.equals(newFullPolicy)) { - mFullPolicy = newFullPolicy; - changed |= (mPolicyLevel == POLICY_LEVEL_FULL); + if (newFullPolicy != null) { + changed |= maybeUpdateDefaultFullPolicy(newFullPolicy); } if (newAdaptivePolicy != null && !mAdaptivePolicy.equals(newAdaptivePolicy)) { @@ -447,13 +450,9 @@ public class BatterySaverPolicy extends ContentObserver implements Slog.i(TAG, "mDeviceSpecificSettings=" + mDeviceSpecificSettings); } - boolean changed = false; - Policy newFullPolicy = Policy.fromSettings(setting, deviceSpecificSetting, - mLastDeviceConfigProperties, null, DEFAULT_FULL_POLICY); - if (mPolicyLevel == POLICY_LEVEL_FULL && !mFullPolicy.equals(newFullPolicy)) { - changed = true; - } - mFullPolicy = newFullPolicy; + boolean changed = maybeUpdateDefaultFullPolicy( + Policy.fromSettings(setting, deviceSpecificSetting, + mLastDeviceConfigProperties, null, DEFAULT_FULL_POLICY)); mDefaultAdaptivePolicy = Policy.fromSettings("", "", mLastDeviceConfigProperties, KEY_SUFFIX_ADAPTIVE, DEFAULT_ADAPTIVE_POLICY); @@ -802,6 +801,33 @@ public class BatterySaverPolicy extends ContentObserver implements ); } + BatterySaverPolicyConfig toConfig() { + return new BatterySaverPolicyConfig.Builder() + .addDeviceSpecificSetting(KEY_CPU_FREQ_INTERACTIVE, + cpuFrequenciesForInteractive.toString()) + .addDeviceSpecificSetting(KEY_CPU_FREQ_NONINTERACTIVE, + cpuFrequenciesForNoninteractive.toString()) + .setAdjustBrightnessFactor(adjustBrightnessFactor) + .setAdvertiseIsEnabled(advertiseIsEnabled) + .setDeferFullBackup(deferFullBackup) + .setDeferKeyValueBackup(deferKeyValueBackup) + .setDisableAnimation(disableAnimation) + .setDisableAod(disableAod) + .setDisableLaunchBoost(disableLaunchBoost) + .setDisableOptionalSensors(disableOptionalSensors) + .setDisableVibration(disableVibration) + .setEnableAdjustBrightness(enableAdjustBrightness) + .setEnableDataSaver(enableDataSaver) + .setEnableFirewall(enableFirewall) + .setEnableNightMode(enableNightMode) + .setEnableQuickDoze(enableQuickDoze) + .setForceAllAppsStandby(forceAllAppsStandby) + .setForceBackgroundCheck(forceBackgroundCheck) + .setLocationMode(locationMode) + .setSoundTriggerMode(soundTriggerMode) + .build(); + } + @VisibleForTesting static Policy fromSettings(String settings, String deviceSpecificSettings, DeviceConfig.Properties properties, String configSuffix) { @@ -1032,6 +1058,11 @@ public class BatterySaverPolicy extends ContentObserver implements if (mPolicyLevel == level) { return false; } + // If we are leaving the full policy level, then any overrides to the full policy set + // through #setFullPolicyLocked should be cleared. + if (mPolicyLevel == POLICY_LEVEL_FULL) { + mFullPolicy = mDefaultFullPolicy; + } switch (level) { case POLICY_LEVEL_FULL: case POLICY_LEVEL_ADAPTIVE: @@ -1047,6 +1078,62 @@ public class BatterySaverPolicy extends ContentObserver implements } } + /** + * Get the current policy for the provided policy level. + */ + Policy getPolicyLocked(@PolicyLevel int policyLevel) { + switch (policyLevel) { + case POLICY_LEVEL_OFF: + return OFF_POLICY; + case POLICY_LEVEL_ADAPTIVE: + return mAdaptivePolicy; + case POLICY_LEVEL_FULL: + return mFullPolicy; + } + + throw new IllegalArgumentException( + "getPolicyLocked: incorrect policy level provided - " + policyLevel); + } + + /** + * Updates the default policy with the passed in policy. + * If the full policy is not overridden with runtime settings, then the full policy will be + * updated. + * + * @return True if the active policy requires an update, false if not. + */ + private boolean maybeUpdateDefaultFullPolicy(Policy p) { + boolean fullPolicyChanged = false; + if (!mDefaultFullPolicy.equals(p)) { + // default policy can be overridden by #setFullPolicyLocked + boolean isDefaultFullPolicyOverridden = !mDefaultFullPolicy.equals(mFullPolicy); + if (!isDefaultFullPolicyOverridden) { + mFullPolicy = p; + fullPolicyChanged = (mPolicyLevel == POLICY_LEVEL_FULL); + } + mDefaultFullPolicy = p; + } + return fullPolicyChanged; + } + + /** @return true if the current policy changed and the policy level is FULL. */ + boolean setFullPolicyLocked(Policy p) { + if (p == null) { + Slog.wtf(TAG, "setFullPolicy given null policy"); + return false; + } + if (mFullPolicy.equals(p)) { + return false; + } + + mFullPolicy = p; + if (mPolicyLevel == POLICY_LEVEL_FULL) { + updatePolicyDependenciesLocked(); + return true; + } + return false; + } + /** @return true if the current policy changed and the policy level is ADAPTIVE. */ boolean setAdaptivePolicyLocked(Policy p) { if (p == null) { @@ -1154,7 +1241,8 @@ public class BatterySaverPolicy extends ContentObserver implements ipw.println("mAutomotiveProjectionActive=" + mAutomotiveProjectionActive.get()); ipw.println("mPolicyLevel=" + mPolicyLevel); - dumpPolicyLocked(ipw, "full", mFullPolicy); + dumpPolicyLocked(ipw, "default full", mDefaultFullPolicy); + dumpPolicyLocked(ipw, "current full", mFullPolicy); dumpPolicyLocked(ipw, "default adaptive", mDefaultAdaptivePolicy); dumpPolicyLocked(ipw, "current adaptive", mAdaptivePolicy); dumpPolicyLocked(ipw, "effective", mEffectivePolicyRaw); diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java index 21500f6490996..04d81d99ff23b 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java @@ -501,6 +501,33 @@ public class BatterySaverStateMachine { } } + /** + * Change the full battery saver policy. + */ + public BatterySaverPolicyConfig getFullBatterySaverPolicy() { + if (DEBUG) { + Slog.d(TAG, "getFullBatterySaverPolicy"); + } + + synchronized (mLock) { + return mBatterySaverController.getPolicyLocked(BatterySaverPolicy.POLICY_LEVEL_FULL); + } + } + + /** + * Change the full battery saver policy. + */ + public boolean setFullBatterySaverPolicy(BatterySaverPolicyConfig config) { + if (DEBUG) { + Slog.d(TAG, "setFullBatterySaverPolicy: config=" + config); + } + + synchronized (mLock) { + return mBatterySaverController.setFullPolicyLocked(config, + BatterySaverController.REASON_FULL_POWER_SAVINGS_CHANGED); + } + } + /** * Enable or disable the current adaptive battery saver policy. This may not change what's in * effect if full battery saver is also enabled. diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 7f35511236f7d..533dc17088962 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -58,6 +58,7 @@ import android.hardware.power.Boost; import android.hardware.power.Mode; import android.os.BatteryManager; import android.os.BatteryManagerInternal; +import android.os.BatterySaverPolicyConfig; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -1143,4 +1144,33 @@ public class PowerManagerServiceTest { assertFalse( mService.getBinderServiceInstance().setPowerModeChecked(Mode.INTERACTIVE, false)); } + + @Test + public void testGetFullPowerSavePolicy_returnsStateMachineResult() { + createService(); + mService.systemReady(null); + BatterySaverPolicyConfig mockReturnConfig = new BatterySaverPolicyConfig.Builder().build(); + when(mBatterySaverStateMachineMock.getFullBatterySaverPolicy()) + .thenReturn(mockReturnConfig); + + mService.getBinderServiceInstance().setPowerSaveModeEnabled(true); + BatterySaverPolicyConfig policyConfig = + mService.getBinderServiceInstance().getFullPowerSavePolicy(); + assertThat(mockReturnConfig).isEqualTo(policyConfig); + verify(mBatterySaverStateMachineMock).getFullBatterySaverPolicy(); + } + + @Test + public void testSetFullPowerSavePolicy_callsStateMachine() { + createService(); + mService.systemReady(null); + BatterySaverPolicyConfig mockSetPolicyConfig = + new BatterySaverPolicyConfig.Builder().build(); + when(mBatterySaverStateMachineMock.setFullBatterySaverPolicy(any())).thenReturn(true); + + mService.getBinderServiceInstance().setPowerSaveModeEnabled(true); + assertThat(mService.getBinderServiceInstance() + .setFullPowerSavePolicy(mockSetPolicyConfig)).isTrue(); + verify(mBatterySaverStateMachineMock).setFullBatterySaverPolicy(eq(mockSetPolicyConfig)); + } } diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java index 4671b09b5cffb..9001b3ddaf8fb 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java @@ -22,6 +22,7 @@ import static com.android.server.power.batterysaver.BatterySaverPolicy.POLICY_LE import static com.google.common.truth.Truth.assertThat; import android.content.Context; +import android.os.BatterySaverPolicyConfig; import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; @@ -595,4 +596,36 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertEquals(PowerManager.LOCATION_MODE_FOREGROUND_ONLY, policy.locationMode); assertEquals(PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY, policy.soundTriggerMode); } + + public void testSetFullPolicy_overridesSettingsAndDeviceConfig_clearOnFullExit() { + mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1; + mMockGlobalSettings.put(Global.BATTERY_SAVER_CONSTANTS, + "location_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, ""); + + mBatterySaverPolicy.onChange(); + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + + Policy currentFullPolicy = mBatterySaverPolicy.getPolicyLocked(POLICY_LEVEL_FULL); + BatterySaverPolicyConfig currentFullPolicyConfig = currentFullPolicy.toConfig(); + BatterySaverPolicyConfig newFullPolicyConfig = + new BatterySaverPolicyConfig.Builder(currentFullPolicyConfig) + .setLocationMode(PowerManager.LOCATION_MODE_FOREGROUND_ONLY) + .build(); + mBatterySaverPolicy.setFullPolicyLocked(Policy.fromConfig(newFullPolicyConfig)); + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_FOREGROUND_ONLY); + + // Any policy settings set through #setFullPolicy will be cleared when exiting full policy. + // Default policy settings will be used on the next full policy mode enter unless + // #setFullPolicy is called again. + mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_OFF); + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_NO_CHANGE); + + mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL); + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + } }