Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
      4 import static android.content.pm.PackageManager.GET_ACTIVITIES;
      5 import static android.content.pm.PackageManager.GET_CONFIGURATIONS;
      6 import static android.content.pm.PackageManager.GET_GIDS;
      7 import static android.content.pm.PackageManager.GET_INSTRUMENTATION;
      8 import static android.content.pm.PackageManager.GET_INTENT_FILTERS;
      9 import static android.content.pm.PackageManager.GET_META_DATA;
     10 import static android.content.pm.PackageManager.GET_PERMISSIONS;
     11 import static android.content.pm.PackageManager.GET_PROVIDERS;
     12 import static android.content.pm.PackageManager.GET_RECEIVERS;
     13 import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
     14 import static android.content.pm.PackageManager.GET_SERVICES;
     15 import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
     16 import static android.content.pm.PackageManager.GET_SIGNATURES;
     17 import static android.content.pm.PackageManager.GET_URI_PERMISSION_PATTERNS;
     18 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
     19 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
     20 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
     21 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
     22 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
     23 import static android.content.pm.PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
     24 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
     25 import static android.content.pm.PackageManager.SIGNATURE_NEITHER_SIGNED;
     26 import static android.content.pm.PackageManager.SIGNATURE_NO_MATCH;
     27 import static android.content.pm.PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
     28 import static android.os.Build.VERSION_CODES.N;
     29 import static java.util.Arrays.asList;
     30 
     31 import android.Manifest;
     32 import android.annotation.UserIdInt;
     33 import android.content.ComponentName;
     34 import android.content.Intent;
     35 import android.content.IntentFilter;
     36 import android.content.IntentSender;
     37 import android.content.pm.ActivityInfo;
     38 import android.content.pm.ApplicationInfo;
     39 import android.content.pm.FeatureInfo;
     40 import android.content.pm.IPackageDataObserver;
     41 import android.content.pm.IPackageDeleteObserver;
     42 import android.content.pm.PackageInfo;
     43 import android.content.pm.PackageManager;
     44 import android.content.pm.PackageManager.NameNotFoundException;
     45 import android.content.pm.PackageParser;
     46 import android.content.pm.PackageParser.Activity;
     47 import android.content.pm.PackageParser.Component;
     48 import android.content.pm.PackageParser.IntentInfo;
     49 import android.content.pm.PackageParser.Package;
     50 import android.content.pm.PackageParser.Service;
     51 import android.content.pm.PackageStats;
     52 import android.content.pm.PackageUserState;
     53 import android.content.pm.PermissionGroupInfo;
     54 import android.content.pm.PermissionInfo;
     55 import android.content.pm.ResolveInfo;
     56 import android.content.pm.ServiceInfo;
     57 import android.content.pm.Signature;
     58 import android.content.res.Resources;
     59 import android.graphics.drawable.Drawable;
     60 import android.net.Uri;
     61 import android.os.Binder;
     62 import android.os.Build;
     63 import android.os.Process;
     64 import android.os.RemoteException;
     65 import android.os.UserHandle;
     66 import android.util.ArraySet;
     67 import android.util.Pair;
     68 import com.google.common.base.Preconditions;
     69 import java.util.ArrayList;
     70 import java.util.Arrays;
     71 import java.util.Collections;
     72 import java.util.Comparator;
     73 import java.util.HashMap;
     74 import java.util.HashSet;
     75 import java.util.Iterator;
     76 import java.util.LinkedHashMap;
     77 import java.util.List;
     78 import java.util.Map;
     79 import java.util.Set;
     80 import java.util.TreeMap;
     81 import org.robolectric.RuntimeEnvironment;
     82 import org.robolectric.annotation.Implementation;
     83 import org.robolectric.annotation.Implements;
     84 import org.robolectric.util.ReflectionHelpers;
     85 import org.robolectric.util.TempDirectory;
     86 
     87 @Implements(PackageManager.class)
     88 public class ShadowPackageManager {
     89 
     90   Map<String, Boolean> permissionRationaleMap = new HashMap<>();
     91   List<FeatureInfo> systemAvailableFeatures = new ArrayList<>();
     92   final Map<String, PackageInfo> packageInfos = new LinkedHashMap<>();
     93   final Map<String, Package> packages = new LinkedHashMap<>();
     94   private Map<String, PackageInfo> packageArchiveInfo = new HashMap<>();
     95   final Map<String, PackageStats> packageStatsMap = new HashMap<>();
     96   final Map<String, String> packageInstallerMap = new HashMap<>();
     97   final Map<Integer, String[]> packagesForUid = new HashMap<>();
     98   final Map<String, Integer> uidForPackage = new HashMap<>();
     99   final Map<Integer, String> namesForUid = new HashMap<>();
    100   final Map<Integer, Integer> verificationResults = new HashMap<>();
    101   final Map<Integer, Long> verificationTimeoutExtension = new HashMap<>();
    102   final Map<String, String> currentToCanonicalNames = new HashMap<>();
    103   final Map<ComponentName, ComponentState> componentList = new LinkedHashMap<>();
    104   final Map<ComponentName, Drawable> drawableList = new LinkedHashMap<>();
    105   final Map<String, Drawable> applicationIcons = new HashMap<>();
    106   final Map<String, Boolean> systemFeatureList = new LinkedHashMap<>();
    107   final Map<IntentFilter, ComponentName> preferredActivities = new LinkedHashMap<>();
    108   final Map<Pair<String, Integer>, Drawable> drawables = new LinkedHashMap<>();
    109   final Map<String, Integer> applicationEnabledSettingMap = new HashMap<>();
    110   Map<String, PermissionInfo> extraPermissions = new HashMap<>();
    111   Map<String, PermissionGroupInfo> extraPermissionGroups = new HashMap<>();
    112   public Map<String, Resources> resources = new HashMap<>();
    113   private final Map<Intent, List<ResolveInfo>> resolveInfoForIntent = new TreeMap<>(new IntentComparator());
    114   private Set<String> deletedPackages = new HashSet<>();
    115   Map<String, IPackageDeleteObserver> pendingDeleteCallbacks = new HashMap<>();
    116 
    117   // From com.android.server.pm.PackageManagerService.compareSignatures().
    118   static int compareSignature(Signature[] signatures1, Signature[] signatures2) {
    119     if (signatures1 == null) {
    120       return (signatures2 == null) ? SIGNATURE_NEITHER_SIGNED
    121           : SIGNATURE_FIRST_NOT_SIGNED;
    122     }
    123     if (signatures2 == null) {
    124       return SIGNATURE_SECOND_NOT_SIGNED;
    125     }
    126     if (signatures1.length != signatures2.length) {
    127       return SIGNATURE_NO_MATCH;
    128     }
    129     HashSet<Signature> signatures1set = new HashSet<>(asList(signatures1));
    130     HashSet<Signature> signatures2set = new HashSet<>(asList(signatures2));
    131     return signatures1set.equals(signatures2set) ? SIGNATURE_MATCH : SIGNATURE_NO_MATCH;
    132   }
    133 
    134   static String resolvePackageName(String packageName, ComponentName componentName) {
    135     String classString = componentName.getClassName();
    136     int index = classString.indexOf('.');
    137     if (index == -1) {
    138       classString = packageName + "." + classString;
    139     } else if (index == 0) {
    140       classString = packageName + classString;
    141     }
    142     return classString;
    143   }
    144 
    145 
    146   static ResolveInfo getResolveInfo(Activity activity, IntentFilter intentFilter) {
    147     ResolveInfo info = new ResolveInfo();
    148     info.isDefault = intentFilter.hasCategory("Intent.CATEGORY_DEFAULT");
    149     info.activityInfo = new ActivityInfo();
    150     info.activityInfo.name = activity.info.name;
    151     info.activityInfo.packageName = activity.info.packageName;
    152     info.activityInfo.applicationInfo = activity.info.applicationInfo;
    153     info.activityInfo.permission = activity.info.permission;
    154     info.filter = new IntentFilter(intentFilter);
    155     return info;
    156   }
    157 
    158   static ResolveInfo getResolveInfo(Service service, IntentFilter intentFilter) {
    159     ResolveInfo info = new ResolveInfo();
    160     info.isDefault = intentFilter.hasCategory("Intent.CATEGORY_DEFAULT");
    161     info.serviceInfo = new ServiceInfo();
    162     info.serviceInfo.name = service.info.name;
    163     info.serviceInfo.packageName = service.info.packageName;
    164     info.serviceInfo.applicationInfo = service.info.applicationInfo;
    165     info.serviceInfo.permission = service.info.permission;
    166     info.filter = new IntentFilter(intentFilter);
    167     return info;
    168   }
    169 
    170   private static void setUpPackageStorage(ApplicationInfo applicationInfo) {
    171     TempDirectory tempDirectory = RuntimeEnvironment.getTempDirectory();
    172     if (applicationInfo.sourceDir == null) {
    173       applicationInfo.sourceDir =
    174           tempDirectory
    175               .createIfNotExists(applicationInfo.packageName + "-sourceDir")
    176               .toAbsolutePath()
    177               .toString();
    178     }
    179     if (applicationInfo.dataDir == null) {
    180       applicationInfo.dataDir =
    181           tempDirectory
    182               .createIfNotExists(applicationInfo.packageName + "-dataDir")
    183               .toAbsolutePath()
    184               .toString();
    185     }
    186     applicationInfo.publicSourceDir = applicationInfo.sourceDir;
    187 
    188     if (RuntimeEnvironment.getApiLevel() >= N) {
    189       applicationInfo.credentialProtectedDataDir = tempDirectory.createIfNotExists("userDataDir").toAbsolutePath().toString();
    190       applicationInfo.deviceProtectedDataDir = tempDirectory.createIfNotExists("deviceDataDir").toAbsolutePath().toString();
    191     }
    192   }
    193 
    194   public void addResolveInfoForIntent(Intent intent, List<ResolveInfo> info) {
    195     resolveInfoForIntent.put(intent, info);
    196   }
    197 
    198   public void addResolveInfoForIntent(Intent intent, ResolveInfo info) {
    199     List<ResolveInfo> infoList = resolveInfoForIntent.get(intent);
    200     if (infoList == null) {
    201       infoList = new ArrayList<>();
    202       resolveInfoForIntent.put(intent, infoList);
    203     }
    204 
    205     infoList.add(info);
    206   }
    207 
    208   public void removeResolveInfosForIntent(Intent intent, String packageName) {
    209     List<ResolveInfo> infoList = resolveInfoForIntent.get(intent);
    210     if (infoList == null) {
    211       infoList = new ArrayList<>();
    212       resolveInfoForIntent.put(intent, infoList);
    213     }
    214 
    215     for (Iterator<ResolveInfo> iterator = infoList.iterator(); iterator.hasNext(); ) {
    216       ResolveInfo resolveInfo = iterator.next();
    217       if (resolveInfo.activityInfo.packageName.equals(packageName)) {
    218         iterator.remove();
    219       }
    220     }
    221   }
    222 
    223   public Drawable getActivityIcon(Intent intent) throws NameNotFoundException {
    224     return drawableList.get(intent.getComponent());
    225   }
    226 
    227   public Drawable getActivityIcon(ComponentName componentName) throws NameNotFoundException {
    228     return drawableList.get(componentName);
    229   }
    230 
    231   public void addActivityIcon(ComponentName component, Drawable drawable) {
    232     drawableList.put(component, drawable);
    233   }
    234 
    235   public void addActivityIcon(Intent intent, Drawable drawable) {
    236     drawableList.put(intent.getComponent(), drawable);
    237   }
    238 
    239   public void setApplicationIcon(String packageName, Drawable drawable) {
    240     applicationIcons.put(packageName, drawable);
    241   }
    242 
    243   public void setApplicationEnabledSetting(String packageName, int newState, int flags) {
    244     applicationEnabledSettingMap.put(packageName, newState);
    245   }
    246 
    247   public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
    248     preferredActivities.put(filter, activity);
    249   }
    250 
    251   public int getPreferredActivities(List<IntentFilter> outFilters, List<ComponentName> outActivities, String packageName) {
    252     if (outFilters == null) {
    253       return 0;
    254     }
    255 
    256     Set<IntentFilter> filters = preferredActivities.keySet();
    257     for (IntentFilter filter : outFilters) {
    258       step:
    259       for (IntentFilter testFilter : filters) {
    260         ComponentName name = preferredActivities.get(testFilter);
    261         // filter out based on the given packageName;
    262         if (packageName != null && !name.getPackageName().equals(packageName)) {
    263           continue step;
    264         }
    265 
    266         // Check actions
    267         Iterator<String> iterator = filter.actionsIterator();
    268         while (iterator.hasNext()) {
    269           if (!testFilter.matchAction(iterator.next())) {
    270             continue step;
    271           }
    272         }
    273 
    274         iterator = filter.categoriesIterator();
    275         while (iterator.hasNext()) {
    276           if (!filter.hasCategory(iterator.next())) {
    277             continue step;
    278           }
    279         }
    280 
    281         if (outActivities == null) {
    282           outActivities = new ArrayList<>();
    283         }
    284 
    285         outActivities.add(name);
    286       }
    287     }
    288 
    289     return 0;
    290   }
    291 
    292   /**
    293    * Return the flags set in call to {@link android.app.ApplicationPackageManager#setComponentEnabledSetting(ComponentName, int, int)}.
    294    *
    295    * @param componentName The component name.
    296    * @return The flags.
    297    */
    298   public int getComponentEnabledSettingFlags(ComponentName componentName) {
    299     ComponentState state = componentList.get(componentName);
    300     return state != null ? state.flags : 0;
    301   }
    302 
    303   /** @deprecated - use {@link #addPackage(PackageInfo)} instead */
    304   @Deprecated
    305   public void addPackage(String packageName) {
    306     PackageInfo packageInfo = new PackageInfo();
    307     packageInfo.packageName = packageName;
    308 
    309     ApplicationInfo applicationInfo = new ApplicationInfo();
    310     applicationInfo.packageName = packageName;
    311     setUpPackageStorage(applicationInfo);
    312     packageInfo.applicationInfo = applicationInfo;
    313     addPackage(packageInfo);
    314   }
    315 
    316   public void addPackage(PackageInfo packageInfo) {
    317     PackageStats packageStats = new PackageStats(packageInfo.packageName);
    318     addPackage(packageInfo, packageStats);
    319   }
    320 
    321   public void addPackage(PackageInfo packageInfo, PackageStats packageStats) {
    322     Preconditions.checkArgument(packageInfo.packageName.equals(packageStats.packageName));
    323 
    324     packageInfos.put(packageInfo.packageName, packageInfo);
    325     packageStatsMap.put(packageInfo.packageName, packageStats);
    326     applicationEnabledSettingMap.put(packageInfo.packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
    327     if (packageInfo.applicationInfo != null) {
    328       namesForUid.put(packageInfo.applicationInfo.uid, packageInfo.packageName);
    329     }
    330   }
    331 
    332   public void addPermissionInfo(PermissionInfo permissionInfo) {
    333     extraPermissions.put(permissionInfo.name, permissionInfo);
    334   }
    335 
    336   /**
    337    * Allows overriding or adding permission-group elements. These would be otherwise specified by
    338    * either the system (https://developer.android.com/guide/topics/permissions/requesting.html#perm-groups)
    339    * or by the app itself, as part of its manifest
    340    * (https://developer.android.com/guide/topics/manifest/permission-group-element.html).
    341    *
    342    * PermissionGroups added through this method have precedence over those specified with the same name
    343    * by one of the aforementioned methods.
    344    */
    345   public void addPermissionGroupInfo(PermissionGroupInfo permissionGroupInfo) {
    346     extraPermissionGroups.put(permissionGroupInfo.name, permissionGroupInfo);
    347   }
    348 
    349   public void removePackage(String packageName) {
    350     packages.remove(packageName);
    351     packageInfos.remove(packageName);
    352   }
    353 
    354   public void setSystemFeature(String name, boolean supported) {
    355     systemFeatureList.put(name, supported);
    356   }
    357 
    358   public void addDrawableResolution(String packageName, int resourceId, Drawable drawable) {
    359     drawables.put(new Pair(packageName, resourceId), drawable);
    360   }
    361 
    362   public Drawable getDrawable(String packageName, int resourceId, ApplicationInfo applicationInfo) {
    363     return drawables.get(new Pair(packageName, resourceId));
    364   }
    365 
    366   public void setNameForUid(int uid, String name) {
    367     namesForUid.put(uid, name);
    368   }
    369 
    370   public void setPackagesForCallingUid(String... packagesForCallingUid) {
    371     packagesForUid.put(Binder.getCallingUid(), packagesForCallingUid);
    372     for (String packageName : packagesForCallingUid) {
    373       uidForPackage.put(packageName, Binder.getCallingUid());
    374     }
    375   }
    376 
    377   public void setPackagesForUid(int uid, String... packagesForCallingUid) {
    378     packagesForUid.put(uid, packagesForCallingUid);
    379     for (String packageName : packagesForCallingUid) {
    380       uidForPackage.put(packageName, uid);
    381     }
    382   }
    383 
    384   public void setPackageArchiveInfo(String archiveFilePath, PackageInfo packageInfo) {
    385     packageArchiveInfo.put(archiveFilePath, packageInfo);
    386   }
    387 
    388   public int getVerificationResult(int id) {
    389     Integer result = verificationResults.get(id);
    390     if (result == null) {
    391       // 0 isn't a "valid" result, so we can check for the case when verification isn't
    392       // called, if needed
    393       return 0;
    394     }
    395     return result;
    396   }
    397 
    398   public long getVerificationExtendedTimeout(int id) {
    399     Long result = verificationTimeoutExtension.get(id);
    400     if (result == null) {
    401       return 0;
    402     }
    403     return result;
    404   }
    405 
    406   public void setShouldShowRequestPermissionRationale(String permission, boolean show) {
    407     permissionRationaleMap.put(permission, show);
    408   }
    409 
    410   public void addSystemAvailableFeature(FeatureInfo featureInfo) {
    411     systemAvailableFeatures.add(featureInfo);
    412   }
    413 
    414   public void clearSystemAvailableFeatures() {
    415     systemAvailableFeatures.clear();
    416   }
    417 
    418   public void addCurrentToCannonicalName(String currentName, String canonicalName) {
    419     currentToCanonicalNames.put(currentName, canonicalName);
    420   }
    421 
    422   @Implementation
    423   public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, UserHandle userHandle) {
    424     return null;
    425   }
    426 
    427   @Implementation
    428   public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, @UserIdInt int userId) {
    429     return null;
    430   }
    431 
    432   @Implementation
    433   public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
    434     List<PackageInfo> result = new ArrayList<>();
    435     for (PackageInfo packageInfo : packageInfos.values()) {
    436       if (applicationEnabledSettingMap.get(packageInfo.packageName)
    437           != COMPONENT_ENABLED_STATE_DISABLED
    438           || (flags & MATCH_UNINSTALLED_PACKAGES) == MATCH_UNINSTALLED_PACKAGES) {
    439             result.add(packageInfo);
    440           }
    441     }
    442 
    443     List<PackageInfo> packages = result;
    444     for (PackageInfo aPackage : packages) {
    445       ApplicationInfo appInfo = aPackage.applicationInfo;
    446       if (appInfo != null && archiveFilePath.equals(appInfo.sourceDir)) {
    447         return aPackage;
    448       }
    449     }
    450     return null;
    451   }
    452 
    453   @Implementation
    454   public void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) {
    455   }
    456 
    457   @Implementation
    458   public void freeStorage(long freeStorageSize, IntentSender pi) {
    459   }
    460 
    461   /**
    462    * Runs the callbacks pending from calls to {@link PackageManager#deletePackage(String, IPackageDeleteObserver, int)}
    463    */
    464   public void doPendingUninstallCallbacks() {
    465     boolean hasDeletePackagesPermission = false;
    466     String[] requestedPermissions =
    467         packageInfos.get(RuntimeEnvironment.application.getPackageName()).requestedPermissions;
    468     if (requestedPermissions != null) {
    469       for (String permission : requestedPermissions) {
    470         if (Manifest.permission.DELETE_PACKAGES.equals(permission)) {
    471           hasDeletePackagesPermission = true;
    472           break;
    473         }
    474       }
    475     }
    476 
    477     for (String packageName : pendingDeleteCallbacks.keySet()) {
    478       int resultCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR;
    479 
    480       PackageInfo removed = packageInfos.get(packageName);
    481       if (hasDeletePackagesPermission && removed != null) {
    482         packageInfos.remove(packageName);
    483         deletedPackages.add(packageName);
    484         resultCode = PackageManager.DELETE_SUCCEEDED;
    485       }
    486 
    487       try {
    488         pendingDeleteCallbacks.get(packageName).packageDeleted(packageName, resultCode);
    489       } catch (RemoteException e) {
    490         throw new RuntimeException(e);
    491       }
    492     }
    493     pendingDeleteCallbacks.clear();
    494   }
    495 
    496   /**
    497    * Returns package names successfully deleted with {@link PackageManager#deletePackage(String, IPackageDeleteObserver, int)}
    498    * Note that like real {@link PackageManager} the calling context must have {@link android.Manifest.permission#DELETE_PACKAGES} permission set.
    499    */
    500   public Set<String> getDeletedPackages() {
    501     return deletedPackages;
    502   }
    503 
    504   protected List<ResolveInfo> queryOverriddenIntents(Intent intent, int flags) {
    505     List<ResolveInfo> result = resolveInfoForIntent.get(intent);
    506     if (result == null) {
    507       return Collections.emptyList();
    508     } else {
    509       return result;
    510     }
    511   }
    512 
    513   public void addPackage(Package appPackage) {
    514     int flags =
    515         GET_ACTIVITIES
    516             | GET_RECEIVERS
    517             | GET_SERVICES
    518             | GET_PROVIDERS
    519             | GET_INSTRUMENTATION
    520             | GET_INTENT_FILTERS
    521             | GET_SIGNATURES
    522             | GET_RESOLVED_FILTER
    523             | GET_META_DATA
    524             | GET_GIDS
    525             | MATCH_DISABLED_COMPONENTS
    526             | GET_SHARED_LIBRARY_FILES
    527             | GET_URI_PERMISSION_PATTERNS
    528             | GET_PERMISSIONS
    529             | MATCH_UNINSTALLED_PACKAGES
    530             | GET_CONFIGURATIONS
    531             | MATCH_DISABLED_UNTIL_USED_COMPONENTS
    532             | MATCH_DIRECT_BOOT_UNAWARE
    533             | MATCH_DIRECT_BOOT_AWARE;
    534 
    535     packages.put(appPackage.packageName, appPackage);
    536     PackageInfo packageInfo;
    537     if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.M) {
    538       packageInfo =
    539           PackageParser.generatePackageInfo(
    540               appPackage,
    541               new int[] {0},
    542               flags,
    543               0,
    544               0,
    545               new HashSet<String>(),
    546               new PackageUserState());
    547     } else if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.LOLLIPOP_MR1) {
    548       packageInfo =
    549           ReflectionHelpers.callStaticMethod(
    550               PackageParser.class,
    551               "generatePackageInfo",
    552               ReflectionHelpers.ClassParameter.from(Package.class, appPackage),
    553               ReflectionHelpers.ClassParameter.from(int[].class, new int[] {0}),
    554               ReflectionHelpers.ClassParameter.from(int.class, flags),
    555               ReflectionHelpers.ClassParameter.from(long.class, 0L),
    556               ReflectionHelpers.ClassParameter.from(long.class, 0L),
    557               ReflectionHelpers.ClassParameter.from(ArraySet.class, new ArraySet<>()),
    558               ReflectionHelpers.ClassParameter.from(
    559                   PackageUserState.class, new PackageUserState()));
    560     } else if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    561       packageInfo =
    562           ReflectionHelpers.callStaticMethod(
    563               PackageParser.class,
    564               "generatePackageInfo",
    565               ReflectionHelpers.ClassParameter.from(Package.class, appPackage),
    566               ReflectionHelpers.ClassParameter.from(int[].class, new int[] {0}),
    567               ReflectionHelpers.ClassParameter.from(int.class, flags),
    568               ReflectionHelpers.ClassParameter.from(long.class, 0L),
    569               ReflectionHelpers.ClassParameter.from(long.class, 0L),
    570               ReflectionHelpers.ClassParameter.from(HashSet.class, new HashSet<>()),
    571               ReflectionHelpers.ClassParameter.from(
    572                   PackageUserState.class, new PackageUserState()));
    573     } else {
    574       packageInfo =
    575           ReflectionHelpers.callStaticMethod(
    576               PackageParser.class,
    577               "generatePackageInfo",
    578               ReflectionHelpers.ClassParameter.from(Package.class, appPackage),
    579               ReflectionHelpers.ClassParameter.from(int[].class, new int[] {0}),
    580               ReflectionHelpers.ClassParameter.from(int.class, flags),
    581               ReflectionHelpers.ClassParameter.from(long.class, 0L),
    582               ReflectionHelpers.ClassParameter.from(long.class, 0L),
    583               ReflectionHelpers.ClassParameter.from(HashSet.class, new HashSet<>()));
    584     }
    585 
    586     packageInfo.applicationInfo.uid = Process.myUid();
    587     addPackage(packageInfo);
    588   }
    589 
    590   public static class IntentComparator implements Comparator<Intent> {
    591 
    592     @Override
    593     public int compare(Intent i1, Intent i2) {
    594       if (i1 == null && i2 == null) return 0;
    595       if (i1 == null && i2 != null) return -1;
    596       if (i1 != null && i2 == null) return 1;
    597       if (i1.equals(i2)) return 0;
    598       String action1 = i1.getAction();
    599       String action2 = i2.getAction();
    600       if (action1 == null && action2 != null) return -1;
    601       if (action1 != null && action2 == null) return 1;
    602       if (action1 != null && action2 != null) {
    603         if (!action1.equals(action2)) {
    604           return action1.compareTo(action2);
    605         }
    606       }
    607       Uri data1 = i1.getData();
    608       Uri data2 = i2.getData();
    609       if (data1 == null && data2 != null) return -1;
    610       if (data1 != null && data2 == null) return 1;
    611       if (data1 != null && data2 != null) {
    612         if (!data1.equals(data2)) {
    613           return data1.compareTo(data2);
    614         }
    615       }
    616       ComponentName component1 = i1.getComponent();
    617       ComponentName component2 = i2.getComponent();
    618       if (component1 == null && component2 != null) return -1;
    619       if (component1 != null && component2 == null) return 1;
    620       if (component1 != null && component2 != null) {
    621         if (!component1.equals(component2)) {
    622           return component1.compareTo(component2);
    623         }
    624       }
    625       String package1 = i1.getPackage();
    626       String package2 = i2.getPackage();
    627       if (package1 == null && package2 != null) return -1;
    628       if (package1 != null && package2 == null) return 1;
    629       if (package1 != null && package2 != null) {
    630         if (!package1.equals(package2)) {
    631           return package1.compareTo(package2);
    632         }
    633       }
    634       Set<String> categories1 = i1.getCategories();
    635       Set<String> categories2 = i2.getCategories();
    636       if (categories1 == null) return categories2 == null ? 0 : -1;
    637       if (categories2 == null) return 1;
    638       if (categories1.size() > categories2.size()) return 1;
    639       if (categories1.size() < categories2.size()) return -1;
    640       String[] array1 = categories1.toArray(new String[0]);
    641       String[] array2 = categories2.toArray(new String[0]);
    642       Arrays.sort(array1);
    643       Arrays.sort(array2);
    644       for (int i = 0; i < array1.length; ++i) {
    645         int val = array1[i].compareTo(array2[i]);
    646         if (val != 0) return val;
    647       }
    648       return 0;
    649     }
    650   }
    651 
    652   protected static class ComponentState {
    653     public int newState;
    654     public int flags;
    655 
    656     public ComponentState(int newState, int flags) {
    657       this.newState = newState;
    658       this.flags = flags;
    659     }
    660   }
    661 
    662   /**
    663    * Get list of intent filters defined for given activity.
    664    *
    665    * @param componentName Name of the activity whose intent filters are to be retrieved
    666    * @return the activity's intent filters
    667    */
    668   public List<IntentFilter> getIntentFiltersForActivity(ComponentName componentName)
    669       throws NameNotFoundException {
    670     return getIntentFiltersForComponent(getAppPackage(componentName).activities, componentName);
    671   }
    672 
    673   /**
    674    * Get list of intent filters defined for given service.
    675    *
    676    * @param componentName Name of the service whose intent filters are to be retrieved
    677    * @return the service's intent filters
    678    */
    679   public List<IntentFilter> getIntentFiltersForService(ComponentName componentName)
    680       throws NameNotFoundException {
    681     return getIntentFiltersForComponent(getAppPackage(componentName).services, componentName);
    682   }
    683 
    684   /**
    685    * Get list of intent filters defined for given receiver.
    686    *
    687    * @param componentName Name of the receiver whose intent filters are to be retrieved
    688    * @return the receiver's intent filters
    689    */
    690   public List<IntentFilter> getIntentFiltersForReceiver(ComponentName componentName)
    691       throws NameNotFoundException {
    692     return getIntentFiltersForComponent(getAppPackage(componentName).receivers, componentName);
    693   }
    694 
    695   private static List<IntentFilter> getIntentFiltersForComponent(
    696       List<? extends Component> components, ComponentName componentName)
    697       throws NameNotFoundException {
    698     for (Component component : components) {
    699       if (component.getComponentName().equals(componentName)) {
    700         return component.intents;
    701       }
    702     }
    703     throw new NameNotFoundException("unknown component " + componentName);
    704   }
    705 
    706   private Package getAppPackage(ComponentName componentName) throws NameNotFoundException {
    707     Package appPackage = this.packages.get(componentName.getPackageName());
    708     if (appPackage == null) {
    709       throw new NameNotFoundException("unknown package " + componentName.getPackageName());
    710     }
    711     return appPackage;
    712   }
    713 
    714   private static List<IntentFilter> convertIntentFilters(
    715       List<? extends PackageParser.IntentInfo> intentInfos) {
    716     List<IntentFilter> intentFilters = new ArrayList<>(intentInfos.size());
    717     for (IntentInfo intentInfo : intentInfos) {
    718       intentFilters.add(intentInfo);
    719     }
    720     return intentFilters;
    721   }
    722 }
    723