• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
newWakeLock(int flags, String tag)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
isScreenOn()42   protected boolean isScreenOn() {
43     return isScreenOn;
44   }
45 
setIsScreenOn(boolean screenOn)46   public void setIsScreenOn(boolean screenOn) {
47     isScreenOn = screenOn;
48   }
49 
50   @Implementation(minSdk = LOLLIPOP)
isInteractive()51   protected boolean isInteractive() {
52     return isInteractive;
53   }
54 
setIsInteractive(boolean interactive)55   public void setIsInteractive(boolean interactive) {
56     isInteractive = interactive;
57   }
58 
59   @Implementation(minSdk = LOLLIPOP)
isPowerSaveMode()60   protected boolean isPowerSaveMode() {
61     return isPowerSaveMode;
62   }
63 
64   @HiddenApi
65   @Implementation(minSdk = KITKAT_WATCH)
setPowerSaveMode(boolean powerSaveMode)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    */
setIsPowerSaveMode(boolean powerSaveMode)82   public void setIsPowerSaveMode(boolean powerSaveMode) {
83     isPowerSaveMode = powerSaveMode;
84   }
85 
86   private Map<Integer, Boolean> supportedWakeLockLevels = new HashMap<>();
87 
88   @Implementation(minSdk = LOLLIPOP)
isWakeLockLevelSupported(int level)89   protected boolean isWakeLockLevelSupported(int level) {
90     return supportedWakeLockLevels.containsKey(level) ? supportedWakeLockLevels.get(level) : false;
91   }
92 
setIsWakeLockLevelSupported(int level, boolean supported)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)
isDeviceIdleMode()101   protected boolean isDeviceIdleMode() {
102     return isDeviceIdleMode;
103   }
104 
105   /** Sets the value returned by {@link #isDeviceIdleMode()}. */
setIsDeviceIdleMode(boolean isDeviceIdleMode)106   public void setIsDeviceIdleMode(boolean isDeviceIdleMode) {
107     this.isDeviceIdleMode = isDeviceIdleMode;
108   }
109 
110   /** Discards the most recent {@code PowerManager.WakeLock}s */
111   @Resetter
reset()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    */
getLatestWakeLock()124   public static PowerManager.WakeLock getLatestWakeLock() {
125     ShadowApplication shadowApplication = Shadow.extract(RuntimeEnvironment.application);
126     return shadowApplication.getLatestWakeLock();
127   }
128 
129   @Implementation(minSdk = M)
isIgnoringBatteryOptimizations(String packageName)130   protected boolean isIgnoringBatteryOptimizations(String packageName) {
131     Boolean result = ignoringBatteryOptimizations.get(packageName);
132     return result == null ? false : result;
133   }
134 
setIgnoringBatteryOptimizations(String packageName, boolean value)135   public void setIgnoringBatteryOptimizations(String packageName, boolean value) {
136     ignoringBatteryOptimizations.put(packageName, Boolean.valueOf(value));
137   }
138 
139   @Implementation
reboot(String reason)140   protected void reboot(String reason) {
141     rebootReasons.add(reason);
142   }
143 
144   /** Returns the number of times {@link #reboot(String)} was called. */
getTimesRebooted()145   public int getTimesRebooted() {
146     return rebootReasons.size();
147   }
148 
149   /** Returns the list of reasons for each reboot, in chronological order. */
getRebootReasons()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
acquire()162     protected void acquire() {
163       acquire(0);
164     }
165 
166     @Implementation
acquire(long timeout)167     protected synchronized void acquire(long timeout) {
168       if (refCounted) {
169         refCount++;
170       } else {
171         locked = true;
172       }
173     }
174 
175     @Implementation
release()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
isHeld()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      */
isReferenceCounted()194     public boolean isReferenceCounted() {
195       return refCounted;
196     }
197 
198     @Implementation
setReferenceCounted(boolean value)199     protected void setReferenceCounted(boolean value) {
200       refCounted = value;
201     }
202 
203     @Implementation
setWorkSource(WorkSource ws)204     protected synchronized void setWorkSource(WorkSource ws) {
205       workSource = ws;
206     }
207 
getWorkSource()208     public synchronized WorkSource getWorkSource() {
209       return workSource;
210     }
211   }
212 }
213