1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.os.cts; 18 19 import static android.os.Flags.batterySaverSupportedCheckApi; 20 21 import static com.android.compatibility.common.util.TestUtils.waitUntil; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertFalse; 25 import static org.junit.Assert.assertNull; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 import android.content.ContentResolver; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.os.PowerManager; 34 import android.os.PowerManager.WakeLock; 35 import android.platform.test.annotations.AppModeFull; 36 import android.provider.Settings.Global; 37 38 import androidx.test.ext.junit.runners.AndroidJUnit4; 39 import androidx.test.filters.LargeTest; 40 import androidx.test.platform.app.InstrumentationRegistry; 41 42 import com.android.compatibility.common.util.BatteryUtils; 43 import com.android.compatibility.common.util.CallbackAsserter; 44 import com.android.compatibility.common.util.SystemUtil; 45 46 import org.junit.After; 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 51 import java.time.Duration; 52 53 @AppModeFull(reason = "Instant Apps don't have the WRITE_SECURE_SETTINGS permission " 54 + "required in tearDown for Global#putInt") 55 @RunWith(AndroidJUnit4.class) 56 public class PowerManagerTest { 57 private static final String TAG = "PowerManagerTest"; 58 public static final long TIME = 3000; 59 public static final int MORE_TIME = 300; 60 private static final int BROADCAST_TIMEOUT_SECONDS = 70; 61 private static final Duration LONG_DISCHARGE_DURATION = Duration.ofMillis(2000); 62 private static final Duration SHORT_DISCHARGE_DURATION = Duration.ofMillis(1000); 63 64 private int mInitialPowerSaverMode; 65 private int mInitialDynamicPowerSavingsEnabled; 66 private int mInitialThreshold; 67 68 /** 69 * test points: 70 * 1 Get a wake lock at the level of the flags parameter 71 * 2 Force the device to go to sleep 72 * 3 User activity happened 73 */ 74 @Test testPowerManager()75 public void testPowerManager() throws InterruptedException { 76 PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 77 78 WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG); 79 wl.acquire(TIME); 80 assertTrue(wl.isHeld()); 81 Thread.sleep(TIME + MORE_TIME); 82 assertFalse(wl.isHeld()); 83 84 try { 85 pm.reboot("Testing"); 86 fail("reboot should throw SecurityException"); 87 } catch (SecurityException e) { 88 // expected 89 } 90 } 91 getContext()92 private Context getContext() { 93 return InstrumentationRegistry.getInstrumentation().getContext(); 94 } 95 96 @Before setUp()97 public void setUp() { 98 // store the current value so we can restore it 99 ContentResolver resolver = getContext().getContentResolver(); 100 mInitialPowerSaverMode = Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, 0); 101 mInitialDynamicPowerSavingsEnabled = 102 Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0); 103 mInitialThreshold = 104 Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 0); 105 106 } 107 108 @After tearDown()109 public void tearDown() { 110 SystemUtil.runWithShellPermissionIdentity(() -> { 111 ContentResolver resolver = getContext().getContentResolver(); 112 113 // Verify we can change it to dynamic. 114 Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, mInitialPowerSaverMode); 115 Global.putInt(resolver, 116 Global.DYNAMIC_POWER_SAVINGS_ENABLED, mInitialDynamicPowerSavingsEnabled); 117 Global.putInt(resolver, 118 Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, mInitialThreshold); 119 }); 120 } 121 122 @Test testPowerManager_getPowerSaveMode()123 public void testPowerManager_getPowerSaveMode() { 124 PowerManager manager = BatteryUtils.getPowerManager(); 125 if (batterySaverSupportedCheckApi() && !manager.isBatterySaverSupported()) { 126 return; 127 } 128 129 SystemUtil.runWithShellPermissionIdentity(() -> { 130 ContentResolver resolver = getContext().getContentResolver(); 131 132 // Verify we can change it to percentage. 133 Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, 0); 134 assertEquals( 135 PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE, 136 manager.getPowerSaveModeTrigger()); 137 138 // Verify we can change it to dynamic. 139 Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, 1); 140 assertEquals( 141 PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC, 142 manager.getPowerSaveModeTrigger()); 143 }); 144 } 145 146 @Test testPowerManager_setDynamicPowerSavings()147 public void testPowerManager_setDynamicPowerSavings() { 148 PowerManager manager = BatteryUtils.getPowerManager(); 149 if (batterySaverSupportedCheckApi() && !manager.isBatterySaverSupported()) { 150 return; 151 } 152 153 SystemUtil.runWithShellPermissionIdentity(() -> { 154 ContentResolver resolver = getContext().getContentResolver(); 155 156 // Verify settings are actually updated. 157 manager.setDynamicPowerSaveHint(true, 80); 158 assertEquals(1, Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0)); 159 assertEquals(80, Global.getInt(resolver, 160 Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 0)); 161 162 manager.setDynamicPowerSaveHint(false, 20); 163 assertEquals(0, Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1)); 164 assertEquals(20, Global.getInt(resolver, 165 Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 0)); 166 }); 167 } 168 169 @LargeTest 170 @Test testPowerManager_batteryDischargePrediction()171 public void testPowerManager_batteryDischargePrediction() throws Exception { 172 final PowerManager manager = BatteryUtils.getPowerManager(); 173 if (batterySaverSupportedCheckApi() && !manager.isBatterySaverSupported()) { 174 return; 175 } 176 177 if (!BatteryUtils.hasBattery()) { 178 assertNull(manager.getBatteryDischargePrediction()); 179 return; 180 } 181 182 // Unplug to ensure the plugged in broadcast is sent. 183 BatteryUtils.runDumpsysBatteryUnplug(); 184 185 // Plugged in. No prediction should be given. 186 final CallbackAsserter pluggedBroadcastAsserter = CallbackAsserter.forBroadcast( 187 new IntentFilter(Intent.ACTION_POWER_CONNECTED)); 188 BatteryUtils.runDumpsysBatterySetPluggedIn(true); 189 pluggedBroadcastAsserter.assertCalled("Didn't get power connected broadcast", 190 BROADCAST_TIMEOUT_SECONDS); 191 // PowerManagerService may get the BATTERY_CHANGED broadcast after we get our broadcast, 192 // so we have to have a little wait. 193 waitUntil("PowerManager doesn't think the device has connected power", 194 () -> manager.getBatteryDischargePrediction() == null); 195 196 // Not plugged in. At the very least, the basic discharge estimation should be returned. 197 final CallbackAsserter unpluggedBroadcastAsserter = CallbackAsserter.forBroadcast( 198 new IntentFilter(Intent.ACTION_POWER_DISCONNECTED)); 199 BatteryUtils.runDumpsysBatteryUnplug(); 200 unpluggedBroadcastAsserter.assertCalled("Didn't get power disconnected broadcast", 201 BROADCAST_TIMEOUT_SECONDS); 202 // PowerManagerService may get the BATTERY_CHANGED broadcast after we get our broadcast, 203 // so we have to have a little wait. 204 waitUntil("PowerManager still thinks the device has connected power", 205 () -> manager.getBatteryDischargePrediction() != null); 206 207 CallbackAsserter predictionChangedBroadcastAsserter = CallbackAsserter.forBroadcast( 208 new IntentFilter(PowerManager.ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED)); 209 setDischargePrediction(LONG_DISCHARGE_DURATION, true); 210 assertDischargePrediction(LONG_DISCHARGE_DURATION, true); 211 predictionChangedBroadcastAsserter.assertCalled("Prediction changed broadcast not received", 212 BROADCAST_TIMEOUT_SECONDS); 213 214 215 predictionChangedBroadcastAsserter = CallbackAsserter.forBroadcast( 216 new IntentFilter(PowerManager.ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED)); 217 setDischargePrediction(SHORT_DISCHARGE_DURATION, false); 218 assertDischargePrediction(SHORT_DISCHARGE_DURATION, false); 219 predictionChangedBroadcastAsserter.assertCalled("Prediction changed broadcast not received", 220 BROADCAST_TIMEOUT_SECONDS); 221 } 222 setDischargePrediction(Duration d, boolean isPersonalized)223 private void setDischargePrediction(Duration d, boolean isPersonalized) { 224 final PowerManager manager = BatteryUtils.getPowerManager(); 225 SystemUtil.runWithShellPermissionIdentity( 226 () -> manager.setBatteryDischargePrediction(d, isPersonalized), 227 android.Manifest.permission.BATTERY_PREDICTION); 228 } 229 assertDischargePrediction(Duration d, boolean isPersonalized)230 private void assertDischargePrediction(Duration d, boolean isPersonalized) { 231 final PowerManager manager = BatteryUtils.getPowerManager(); 232 // We can't pause time so must use >= because the time remaining should decrease as 233 // time goes on. 234 Duration prediction = manager.getBatteryDischargePrediction(); 235 assertTrue("Prediction is greater than " + d.toMillis() + "ms: " 236 + prediction, d.toMillis() >= prediction.toMillis()); 237 assertEquals(isPersonalized, manager.isBatteryDischargePredictionPersonalized()); 238 } 239 } 240