Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.os.Build.VERSION_CODES.KITKAT;
      4 
      5 import android.app.AppOpsManager;
      6 import android.app.AppOpsManager.OpEntry;
      7 import android.app.AppOpsManager.PackageOps;
      8 import android.os.Build;
      9 import com.google.common.collect.HashMultimap;
     10 import com.google.common.collect.ImmutableList;
     11 import com.google.common.collect.Multimap;
     12 import java.util.ArrayList;
     13 import java.util.HashSet;
     14 import java.util.List;
     15 import java.util.Set;
     16 import org.robolectric.RuntimeEnvironment;
     17 import org.robolectric.annotation.HiddenApi;
     18 import org.robolectric.annotation.Implementation;
     19 import org.robolectric.annotation.Implements;
     20 import org.robolectric.util.ReflectionHelpers;
     21 import org.robolectric.util.ReflectionHelpers.ClassParameter;
     22 
     23 /**
     24  * Shadow for the {@link AppOpsManager}.
     25  */
     26 @Implements(value = AppOpsManager.class)
     27 public class ShadowAppOpsManager {
     28 
     29   // OpEntry fields that the shadow doesn't currently allow the test to configure.
     30   private static final long OP_TIME = 1400000000L;
     31   private static final long REJECT_TIME = 0L;
     32   private static final int DURATION = 10;
     33   private static final int PROXY_UID = 0;
     34   private static final String PROXY_PACKAGE = "";
     35 
     36   // Recorded operations, keyed by "uid|packageName"
     37   Multimap<String, Integer> mStoredOps = HashMultimap.create();
     38 
     39   @Implementation(minSdk = KITKAT)
     40   public int noteOp(int op, int uid, String packageName) {
     41     mStoredOps.put(getInternalKey(uid, packageName), op);
     42 
     43     // Permission check not currently implemented in this shadow.
     44     return AppOpsManager.MODE_ALLOWED;
     45   }
     46 
     47   @Implementation(minSdk = KITKAT)
     48   @HiddenApi
     49   public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
     50     Set<Integer> opFilter = new HashSet<>();
     51     if (ops != null) {
     52       for (int op : ops) {
     53         opFilter.add(op);
     54       }
     55     }
     56 
     57     List<OpEntry> opEntries = new ArrayList<>();
     58     for (Integer op : mStoredOps.get(getInternalKey(uid, packageName))) {
     59       if (opFilter.isEmpty() || opFilter.contains(op)) {
     60         opEntries.add(toOpEntry(op));
     61       }
     62     }
     63 
     64     return ImmutableList.of(new PackageOps(packageName, uid, opEntries));
     65   }
     66 
     67   private static OpEntry toOpEntry(Integer op) {
     68     if (RuntimeEnvironment.getApiLevel() < Build.VERSION_CODES.M) {
     69       return (OpEntry) ReflectionHelpers.callConstructor(
     70           OpEntry.class,
     71           ClassParameter.from(int.class, op),
     72           ClassParameter.from(int.class, AppOpsManager.MODE_ALLOWED),
     73           ClassParameter.from(long.class, OP_TIME),
     74           ClassParameter.from(long.class, REJECT_TIME),
     75           ClassParameter.from(int.class, DURATION));
     76     }
     77 
     78     return new OpEntry(
     79         op, AppOpsManager.MODE_ALLOWED, OP_TIME, REJECT_TIME, DURATION, PROXY_UID, PROXY_PACKAGE);
     80   }
     81 
     82   private static String getInternalKey(int uid, String packageName) {
     83     return uid + "|" + packageName;
     84   }
     85 }
     86