Home | History | Annotate | Download | only in shadows
      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