1 /* 2 * Copyright (C) 2018 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 package com.android.compatibility.common.util; 17 18 import static android.os.Flags.batterySaverSupportedCheckApi; 19 20 import static com.android.compatibility.common.util.TestUtils.waitUntil; 21 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.pm.PackageManager; 25 import android.os.BatteryManager; 26 import android.os.PowerManager; 27 import android.provider.Settings.Global; 28 import android.util.Log; 29 30 import androidx.test.InstrumentationRegistry; 31 32 import com.android.compatibility.common.util.UserSettings.Namespace; 33 34 import org.junit.Assume; 35 36 public class BatteryUtils { 37 private static final String TAG = "CtsBatteryUtils"; 38 BatteryUtils()39 private BatteryUtils() { 40 } 41 getBatteryManager()42 public static BatteryManager getBatteryManager() { 43 return InstrumentationRegistry.getContext().getSystemService(BatteryManager.class); 44 } 45 getPowerManager()46 public static PowerManager getPowerManager() { 47 return InstrumentationRegistry.getContext().getSystemService(PowerManager.class); 48 } 49 hasBattery()50 public static boolean hasBattery() { 51 final Intent batteryInfo = InstrumentationRegistry.getContext() 52 .registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 53 return batteryInfo != null 54 && batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); 55 } 56 57 /** Make the target device think it's off charger. */ runDumpsysBatteryUnplug()58 public static void runDumpsysBatteryUnplug() throws Exception { 59 SystemUtil.runShellCommandForNoOutput("cmd battery unplug"); 60 61 waitForPlugStatus(false); 62 63 Log.d(TAG, "Battery UNPLUGGED"); 64 } 65 66 /** 67 * Set the battery level to {@code level} percent. The valid range is [0, 100]. 68 */ runDumpsysBatterySetLevel(int level)69 public static void runDumpsysBatterySetLevel(int level) throws Exception { 70 SystemUtil.runShellCommandForNoOutput(("cmd battery set level " + level)); 71 72 Log.d(TAG, "Battery level set to " + level); 73 } 74 75 /** 76 * Set whether the device is plugged in to a charger or not. 77 */ runDumpsysBatterySetPluggedIn(boolean pluggedIn)78 public static void runDumpsysBatterySetPluggedIn(boolean pluggedIn) throws Exception { 79 SystemUtil.runShellCommandForNoOutput(("cmd battery set ac " + (pluggedIn ? "1" : "0"))); 80 81 waitForPlugStatus(pluggedIn); 82 83 Log.d(TAG, "Battery AC set to " + pluggedIn); 84 } 85 waitForPlugStatus(boolean pluggedIn)86 private static void waitForPlugStatus(boolean pluggedIn) throws Exception { 87 if (InstrumentationRegistry.getContext().getPackageManager().isInstantApp()) { 88 // Instant apps are not allowed to query ACTION_BATTERY_CHANGED. Add short sleep as 89 // best-effort wait for status. 90 Thread.sleep(2000); 91 return; 92 } 93 IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 94 waitUntil("Device still " + (pluggedIn ? " not plugged" : " plugged"), 95 () -> { 96 Intent batteryStatus = 97 InstrumentationRegistry.getContext().registerReceiver(null, ifilter); 98 int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); 99 return pluggedIn == (chargePlug != 0); 100 }); 101 } 102 103 /** Reset the effect of all the previous {@code runDumpsysBattery*} call */ runDumpsysBatteryReset()104 public static void runDumpsysBatteryReset() { 105 SystemUtil.runShellCommandForNoOutput(("cmd battery reset")); 106 107 Log.d(TAG, "Battery RESET"); 108 } 109 enableAdaptiveBatterySaver(boolean enabled)110 public static void enableAdaptiveBatterySaver(boolean enabled) { 111 final String setting = enabled ? "true" : "false"; 112 SystemUtil.runShellCommandForNoOutput( 113 "cmd power set-adaptive-power-saver-enabled " + setting); 114 } 115 116 /** 117 * Enable / disable battery saver. Note {@link #runDumpsysBatteryUnplug} must have been executed 118 * before enabling BS. Always wait until battery saver is turned on or off according to the 119 * input. So this method can only be used for battery saver is supported. 120 */ enableBatterySaver(boolean enabled)121 public static void enableBatterySaver(boolean enabled) throws Exception { 122 enableBatterySaver(enabled, /* shouldWait= */ true); 123 } 124 125 /** 126 * Enable / disable battery saver. Note {@link #runDumpsysBatteryUnplug} must have been 127 * executed before enabling BS. Only wait until battery saver when required. 128 */ enableBatterySaver(boolean enabled, boolean shouldWait)129 public static void enableBatterySaver(boolean enabled, boolean shouldWait) throws Exception { 130 UserSettings globalSettings = new UserSettings(Namespace.GLOBAL); 131 if (enabled) { 132 SystemUtil.runShellCommandForNoOutput("cmd power set-mode 1"); 133 AmUtils.waitForBroadcastBarrier(); 134 globalSettings.set(Global.LOW_POWER_MODE, "1"); 135 if (shouldWait) { 136 waitUntil("Battery saver still off", () -> getPowerManager().isPowerSaveMode()); 137 } 138 } else { 139 SystemUtil.runShellCommandForNoOutput("cmd power set-mode 0"); 140 AmUtils.waitForBroadcastBarrier(); 141 globalSettings.set(Global.LOW_POWER_MODE, "0"); 142 globalSettings.set(Global.LOW_POWER_MODE_STICKY, "0"); 143 if (shouldWait) { 144 waitUntil("Battery saver still on", () -> !getPowerManager().isPowerSaveMode()); 145 } 146 } 147 148 AmUtils.waitForBroadcastBarrier(); 149 Log.d(TAG, "Battery saver turned " + (enabled ? "ON" : "OFF")); 150 } 151 152 /** Reset battery saver state and take it out of a forced state. */ resetBatterySaver()153 public static void resetBatterySaver() throws Exception { 154 UserSettings globalSettings = new UserSettings(Namespace.GLOBAL); 155 SystemUtil.runShellCommandForNoOutput("cmd power set-mode 0"); 156 globalSettings.set(Global.LOW_POWER_MODE, null); 157 globalSettings.set(Global.LOW_POWER_MODE_STICKY, null); 158 waitUntil("Battery saver still on", () -> !getPowerManager().isPowerSaveMode()); 159 } 160 161 /** 162 * Turn on/off screen. 163 */ turnOnScreen(boolean on)164 public static void turnOnScreen(boolean on) throws Exception { 165 if (on) { 166 SystemUtil.runShellCommandForNoOutput("input keyevent KEYCODE_WAKEUP"); 167 waitUntil("Device still not interactive", () -> getPowerManager().isInteractive()); 168 169 } else { 170 SystemUtil.runShellCommandForNoOutput("input keyevent KEYCODE_SLEEP"); 171 waitUntil("Device still interactive", () -> !getPowerManager().isInteractive()); 172 } 173 AmUtils.waitForBroadcastBarrier(); 174 Log.d(TAG, "Screen turned " + (on ? "ON" : "OFF")); 175 } 176 177 /** @return true if the device supports battery saver. */ isBatterySaverSupported()178 public static boolean isBatterySaverSupported() { 179 final PowerManager powerManager = getPowerManager(); 180 if (batterySaverSupportedCheckApi() && !powerManager.isBatterySaverSupported()) { 181 // Battery saver configuration has been turned off for devices. 182 return false; 183 } 184 185 if (!hasBattery()) { 186 // Devices without a battery don't support battery saver. 187 return false; 188 } 189 190 final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager(); 191 return !(pm.hasSystemFeature(PackageManager.FEATURE_WATCH) || 192 pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)); 193 } 194 195 /** "Assume" the current device supports battery saver. */ assumeBatterySaverFeature()196 public static void assumeBatterySaverFeature() { 197 Assume.assumeTrue("Device doesn't support battery saver", isBatterySaverSupported()); 198 } 199 } 200