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