1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.KITKAT_WATCH; 4 import static android.os.Build.VERSION_CODES.LOLLIPOP; 5 import static android.os.Build.VERSION_CODES.M; 6 import static org.robolectric.shadows.ShadowApplication.getInstance; 7 8 import android.Manifest.permission; 9 import android.content.Context; 10 import android.content.pm.PackageManager; 11 import android.os.PowerManager; 12 import android.os.WorkSource; 13 import com.google.common.collect.ImmutableList; 14 import java.util.ArrayList; 15 import java.util.HashMap; 16 import java.util.List; 17 import java.util.Map; 18 import org.robolectric.RuntimeEnvironment; 19 import org.robolectric.annotation.HiddenApi; 20 import org.robolectric.annotation.Implementation; 21 import org.robolectric.annotation.Implements; 22 import org.robolectric.annotation.Resetter; 23 import org.robolectric.shadow.api.Shadow; 24 25 @Implements(PowerManager.class) 26 public class ShadowPowerManager { 27 private boolean isScreenOn = true; 28 private boolean isInteractive = true; 29 private boolean isPowerSaveMode = false; 30 private boolean isDeviceIdleMode = false; 31 private List<String> rebootReasons = new ArrayList<String>(); 32 private Map<String, Boolean> ignoringBatteryOptimizations = new HashMap<>(); 33 34 @Implementation 35 protected PowerManager.WakeLock newWakeLock(int flags, String tag) { 36 PowerManager.WakeLock wl = Shadow.newInstanceOf(PowerManager.WakeLock.class); 37 getInstance().addWakeLock(wl); 38 return wl; 39 } 40 41 @Implementation 42 protected boolean isScreenOn() { 43 return isScreenOn; 44 } 45 46 public void setIsScreenOn(boolean screenOn) { 47 isScreenOn = screenOn; 48 } 49 50 @Implementation(minSdk = LOLLIPOP) 51 protected boolean isInteractive() { 52 return isInteractive; 53 } 54 55 public void setIsInteractive(boolean interactive) { 56 isInteractive = interactive; 57 } 58 59 @Implementation(minSdk = LOLLIPOP) 60 protected boolean isPowerSaveMode() { 61 return isPowerSaveMode; 62 } 63 64 @HiddenApi 65 @Implementation(minSdk = KITKAT_WATCH) 66 protected boolean setPowerSaveMode(boolean powerSaveMode) { 67 final Context context = RuntimeEnvironment.application; 68 final int perm = context.getPackageManager() 69 .checkPermission(permission.DEVICE_POWER, context.getPackageName()); 70 if (perm != PackageManager.PERMISSION_GRANTED) { 71 throw new SecurityException( 72 "You need DEVICE_POWER permission to: set the device power-save mode"); 73 } 74 isPowerSaveMode = powerSaveMode; 75 return true; 76 } 77 78 /** 79 * Alters the power-save mode without verifying that the package under test has the required 80 * permission. 81 */ 82 public void setIsPowerSaveMode(boolean powerSaveMode) { 83 isPowerSaveMode = powerSaveMode; 84 } 85 86 private Map<Integer, Boolean> supportedWakeLockLevels = new HashMap<>(); 87 88 @Implementation(minSdk = LOLLIPOP) 89 protected boolean isWakeLockLevelSupported(int level) { 90 return supportedWakeLockLevels.containsKey(level) ? supportedWakeLockLevels.get(level) : false; 91 } 92 93 public void setIsWakeLockLevelSupported(int level, boolean supported) { 94 supportedWakeLockLevels.put(level, supported); 95 } 96 97 /** 98 * @return `false` by default, or the value specified via {@link #setIsDeviceIdleMode(boolean)} 99 */ 100 @Implementation(minSdk = M) 101 protected boolean isDeviceIdleMode() { 102 return isDeviceIdleMode; 103 } 104 105 /** Sets the value returned by {@link #isDeviceIdleMode()}. */ 106 public void setIsDeviceIdleMode(boolean isDeviceIdleMode) { 107 this.isDeviceIdleMode = isDeviceIdleMode; 108 } 109 110 /** Discards the most recent {@code PowerManager.WakeLock}s */ 111 @Resetter 112 public static void reset() { 113 ShadowApplication shadowApplication = ShadowApplication.getInstance(); 114 if (shadowApplication != null) { 115 shadowApplication.clearWakeLocks(); 116 } 117 } 118 119 /** 120 * Retrieves the most recent wakelock registered by the application 121 * 122 * @return Most recent wake lock. 123 */ 124 public static PowerManager.WakeLock getLatestWakeLock() { 125 ShadowApplication shadowApplication = Shadow.extract(RuntimeEnvironment.application); 126 return shadowApplication.getLatestWakeLock(); 127 } 128 129 @Implementation(minSdk = M) 130 protected boolean isIgnoringBatteryOptimizations(String packageName) { 131 Boolean result = ignoringBatteryOptimizations.get(packageName); 132 return result == null ? false : result; 133 } 134 135 public void setIgnoringBatteryOptimizations(String packageName, boolean value) { 136 ignoringBatteryOptimizations.put(packageName, Boolean.valueOf(value)); 137 } 138 139 @Implementation 140 protected void reboot(String reason) { 141 rebootReasons.add(reason); 142 } 143 144 /** Returns the number of times {@link #reboot(String)} was called. */ 145 public int getTimesRebooted() { 146 return rebootReasons.size(); 147 } 148 149 /** Returns the list of reasons for each reboot, in chronological order. */ 150 public ImmutableList<String> getRebootReasons() { 151 return ImmutableList.copyOf(rebootReasons); 152 } 153 154 @Implements(PowerManager.WakeLock.class) 155 public static class ShadowWakeLock { 156 private boolean refCounted = true; 157 private int refCount = 0; 158 private boolean locked = false; 159 private WorkSource workSource = null; 160 161 @Implementation 162 protected void acquire() { 163 acquire(0); 164 } 165 166 @Implementation 167 protected synchronized void acquire(long timeout) { 168 if (refCounted) { 169 refCount++; 170 } else { 171 locked = true; 172 } 173 } 174 175 @Implementation 176 protected synchronized void release() { 177 if (refCounted) { 178 if (--refCount < 0) throw new RuntimeException("WakeLock under-locked"); 179 } else { 180 locked = false; 181 } 182 } 183 184 @Implementation 185 protected synchronized boolean isHeld() { 186 return refCounted ? refCount > 0 : locked; 187 } 188 189 /** 190 * Retrieves if the wake lock is reference counted or not 191 * 192 * @return Is the wake lock reference counted? 193 */ 194 public boolean isReferenceCounted() { 195 return refCounted; 196 } 197 198 @Implementation 199 protected void setReferenceCounted(boolean value) { 200 refCounted = value; 201 } 202 203 @Implementation 204 protected synchronized void setWorkSource(WorkSource ws) { 205 workSource = ws; 206 } 207 208 public synchronized WorkSource getWorkSource() { 209 return workSource; 210 } 211 } 212 } 213