Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.content.pm.ApplicationInfo.FLAG_ALLOW_BACKUP;
      4 import static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
      5 import static android.content.pm.ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
      6 import static android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE;
      7 import static android.content.pm.ApplicationInfo.FLAG_HAS_CODE;
      8 import static android.content.pm.ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
      9 import static android.content.pm.ApplicationInfo.FLAG_PERSISTENT;
     10 import static android.content.pm.ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
     11 import static android.content.pm.ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
     12 import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
     13 import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
     14 import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
     15 import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
     16 import static android.content.pm.ApplicationInfo.FLAG_TEST_ONLY;
     17 import static android.content.pm.ApplicationInfo.FLAG_VM_SAFE_MODE;
     18 import static android.os.Build.VERSION_CODES.LOLLIPOP;
     19 import static android.os.PatternMatcher.PATTERN_LITERAL;
     20 import static android.os.PatternMatcher.PATTERN_PREFIX;
     21 import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
     22 import static java.util.Arrays.asList;
     23 
     24 import android.content.IntentFilter.MalformedMimeTypeException;
     25 import android.content.pm.ActivityInfo;
     26 import android.content.pm.ComponentInfo;
     27 import android.content.pm.PackageInfo;
     28 import android.content.pm.PackageItemInfo;
     29 import android.content.pm.PackageParser;
     30 import android.content.pm.PackageParser.Activity;
     31 import android.content.pm.PackageParser.ActivityIntentInfo;
     32 import android.content.pm.PackageParser.IntentInfo;
     33 import android.content.pm.PackageParser.Package;
     34 import android.content.pm.PackageParser.Permission;
     35 import android.content.pm.PackageParser.PermissionGroup;
     36 import android.content.pm.PackageParser.Service;
     37 import android.content.pm.PackageParser.ServiceIntentInfo;
     38 import android.content.pm.PathPermission;
     39 import android.content.pm.PermissionGroupInfo;
     40 import android.content.pm.PermissionInfo;
     41 import android.content.pm.ProviderInfo;
     42 import android.content.pm.ServiceInfo;
     43 import android.os.Build;
     44 import android.os.Build.VERSION_CODES;
     45 import android.os.Bundle;
     46 import android.os.Process;
     47 import android.util.Pair;
     48 import com.google.common.base.Strings;
     49 import java.util.ArrayList;
     50 import java.util.Arrays;
     51 import java.util.List;
     52 import java.util.Map;
     53 import org.robolectric.RuntimeEnvironment;
     54 import org.robolectric.manifest.ActivityData;
     55 import org.robolectric.manifest.AndroidManifest;
     56 import org.robolectric.manifest.BroadcastReceiverData;
     57 import org.robolectric.manifest.ContentProviderData;
     58 import org.robolectric.manifest.IntentFilterData;
     59 import org.robolectric.manifest.IntentFilterData.DataAuthority;
     60 import org.robolectric.manifest.PackageItemData;
     61 import org.robolectric.manifest.PathPermissionData;
     62 import org.robolectric.manifest.PermissionGroupItemData;
     63 import org.robolectric.manifest.PermissionItemData;
     64 import org.robolectric.manifest.ServiceData;
     65 import org.robolectric.res.AttributeResource;
     66 import org.robolectric.res.ResName;
     67 import org.robolectric.util.ReflectionHelpers;
     68 
     69 /** Creates a {@link PackageInfo} from a {@link AndroidManifest} */
     70 public class LegacyManifestParser {
     71 
     72   private static final List<Pair<String, Integer>> APPLICATION_FLAGS =
     73       asList(
     74           Pair.create("android:allowBackup", FLAG_ALLOW_BACKUP),
     75           Pair.create("android:allowClearUserData", FLAG_ALLOW_CLEAR_USER_DATA),
     76           Pair.create("android:allowTaskReparenting", FLAG_ALLOW_TASK_REPARENTING),
     77           Pair.create("android:debuggable", FLAG_DEBUGGABLE),
     78           Pair.create("android:hasCode", FLAG_HAS_CODE),
     79           Pair.create("android:killAfterRestore", FLAG_KILL_AFTER_RESTORE),
     80           Pair.create("android:persistent", FLAG_PERSISTENT),
     81           Pair.create("android:resizeable", FLAG_RESIZEABLE_FOR_SCREENS),
     82           Pair.create("android:restoreAnyVersion", FLAG_RESTORE_ANY_VERSION),
     83           Pair.create("android:largeScreens", FLAG_SUPPORTS_LARGE_SCREENS),
     84           Pair.create("android:normalScreens", FLAG_SUPPORTS_NORMAL_SCREENS),
     85           Pair.create("android:anyDensity", FLAG_SUPPORTS_SCREEN_DENSITIES),
     86           Pair.create("android:smallScreens", FLAG_SUPPORTS_SMALL_SCREENS),
     87           Pair.create("android:testOnly", FLAG_TEST_ONLY),
     88           Pair.create("android:vmSafeMode", FLAG_VM_SAFE_MODE));
     89   private static final List<Pair<String, Integer>> CONFIG_OPTIONS =
     90       asList(
     91           Pair.create("mcc", ActivityInfo.CONFIG_MCC),
     92           Pair.create("mnc", ActivityInfo.CONFIG_MNC),
     93           Pair.create("locale", ActivityInfo.CONFIG_LOCALE),
     94           Pair.create("touchscreen", ActivityInfo.CONFIG_TOUCHSCREEN),
     95           Pair.create("keyboard", ActivityInfo.CONFIG_KEYBOARD),
     96           Pair.create("keyboardHidden", ActivityInfo.CONFIG_KEYBOARD_HIDDEN),
     97           Pair.create("navigation", ActivityInfo.CONFIG_NAVIGATION),
     98           Pair.create("screenLayout", ActivityInfo.CONFIG_SCREEN_LAYOUT),
     99           Pair.create("fontScale", ActivityInfo.CONFIG_FONT_SCALE),
    100           Pair.create("uiMode", ActivityInfo.CONFIG_UI_MODE),
    101           Pair.create("orientation", ActivityInfo.CONFIG_ORIENTATION),
    102           Pair.create("screenSize", ActivityInfo.CONFIG_SCREEN_SIZE),
    103           Pair.create("smallestScreenSize", ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE));
    104 
    105   public static Package createPackage(AndroidManifest androidManifest) {
    106 
    107     Package pkg = new Package(androidManifest.getPackageName());
    108 
    109     pkg.mVersionName = androidManifest.getVersionName();
    110     pkg.mVersionCode = androidManifest.getVersionCode();
    111 
    112     Map<String, PermissionItemData> permissionItemData = androidManifest.getPermissions();
    113     for (PermissionItemData itemData : permissionItemData.values()) {
    114       Permission permission = new Permission(pkg, createPermissionInfo(pkg, itemData));
    115       permission.metaData = permission.info.metaData;
    116       pkg.permissions.add(permission);
    117     }
    118 
    119     Map<String, PermissionGroupItemData> permissionGroupItemData =
    120         androidManifest.getPermissionGroups();
    121     for (PermissionGroupItemData itemData : permissionGroupItemData.values()) {
    122       PermissionGroup permissionGroup =
    123           new PermissionGroup(pkg, createPermissionGroupInfo(pkg, itemData));
    124       permissionGroup.metaData = permissionGroup.info.metaData;
    125       pkg.permissionGroups.add(permissionGroup);
    126     }
    127 
    128     pkg.requestedPermissions.addAll(androidManifest.getUsedPermissions());
    129     if (RuntimeEnvironment.getApiLevel() < VERSION_CODES.M) {
    130       List<Boolean> permissionsRequired =
    131           ReflectionHelpers.getField(pkg, "requestedPermissionsRequired");
    132       permissionsRequired.addAll(buildBooleanList(pkg.requestedPermissions.size(), true));
    133     }
    134 
    135     pkg.applicationInfo.flags = decodeFlags(androidManifest.getApplicationAttributes());
    136     pkg.applicationInfo.targetSdkVersion = androidManifest.getTargetSdkVersion();
    137     pkg.applicationInfo.packageName = androidManifest.getPackageName();
    138     pkg.applicationInfo.processName = androidManifest.getProcessName();
    139     if (!Strings.isNullOrEmpty(androidManifest.getApplicationName())) {
    140       pkg.applicationInfo.className =
    141           buildClassName(pkg.applicationInfo.packageName, androidManifest.getApplicationName());
    142       if (RuntimeEnvironment.getApiLevel() >= VERSION_CODES.N_MR1) {
    143         pkg.applicationInfo.name = pkg.applicationInfo.className;
    144       }
    145     }
    146     pkg.applicationInfo.metaData = metaDataToBundle(androidManifest.getApplicationMetaData());
    147     pkg.applicationInfo.uid = Process.myUid();
    148     if (androidManifest.getThemeRef() != null) {
    149       pkg.applicationInfo.theme =
    150           RuntimeEnvironment.getAppResourceTable()
    151               .getResourceId(
    152                   ResName.qualifyResName(
    153                       androidManifest.getThemeRef().replace("@", ""), pkg.packageName, "style"));
    154     }
    155 
    156     int labelRes = 0;
    157     if (androidManifest.getLabelRef() != null) {
    158       String fullyQualifiedName =
    159           ResName.qualifyResName(androidManifest.getLabelRef(), androidManifest.getPackageName());
    160       Integer id =
    161           fullyQualifiedName == null
    162               ? null
    163               : RuntimeEnvironment.getAppResourceTable()
    164                   .getResourceId(new ResName(fullyQualifiedName));
    165       labelRes = id != null ? id : 0;
    166     }
    167 
    168     pkg.applicationInfo.labelRes = labelRes;
    169     String labelRef = androidManifest.getLabelRef();
    170     if (labelRef != null && !labelRef.startsWith("@")) {
    171       pkg.applicationInfo.nonLocalizedLabel = labelRef;
    172     }
    173 
    174     Map<String, ActivityData> activityDatas = androidManifest.getActivityDatas();
    175     for (ActivityData data : activityDatas.values()) {
    176       ActivityInfo activityInfo = new ActivityInfo();
    177       activityInfo.name = buildClassName(pkg.packageName, data.getName());
    178       activityInfo.packageName = pkg.packageName;
    179       activityInfo.configChanges = getConfigChanges(data);
    180       activityInfo.parentActivityName = data.getParentActivityName();
    181       activityInfo.metaData = metaDataToBundle(data.getMetaData().getValueMap());
    182       activityInfo.applicationInfo = pkg.applicationInfo;
    183       activityInfo.targetActivity = data.getTargetActivityName();
    184       activityInfo.exported = data.isExported();
    185       activityInfo.permission = data.getPermission();
    186       activityInfo.enabled = data.isEnabled();
    187       String themeRef;
    188 
    189       // Based on ShadowActivity
    190       if (data.getThemeRef() != null) {
    191         themeRef = data.getThemeRef();
    192       } else {
    193         themeRef = androidManifest.getThemeRef();
    194       }
    195       if (themeRef != null) {
    196         activityInfo.theme =
    197             RuntimeEnvironment.getAppResourceTable()
    198                 .getResourceId(
    199                     ResName.qualifyResName(themeRef.replace("@", ""), pkg.packageName, "style"));
    200       }
    201 
    202       if (data.getLabel() != null) {
    203         activityInfo.labelRes =
    204             RuntimeEnvironment.getAppResourceTable()
    205                 .getResourceId(
    206                     ResName.qualifyResName(
    207                         data.getLabel().replace("@", ""), pkg.packageName, "string"));
    208         if (activityInfo.labelRes == 0) {
    209           activityInfo.nonLocalizedLabel = data.getLabel();
    210         }
    211       }
    212 
    213       Activity activity = createActivity(pkg, activityInfo);
    214       for (IntentFilterData intentFilterData : data.getIntentFilters()) {
    215         ActivityIntentInfo outInfo = new ActivityIntentInfo(activity);
    216         populateIntentInfo(intentFilterData, outInfo);
    217         activity.intents.add(outInfo);
    218       }
    219       pkg.activities.add(activity);
    220     }
    221 
    222     for (ContentProviderData data : androidManifest.getContentProviders()) {
    223       ProviderInfo info = new ProviderInfo();
    224       populateComponentInfo(info, pkg, data);
    225       info.authority = data.getAuthorities();
    226 
    227       List<PathPermission> permissions = new ArrayList<>();
    228       for (PathPermissionData permissionData : data.getPathPermissionDatas()) {
    229         permissions.add(createPathPermission(permissionData));
    230       }
    231       info.pathPermissions = permissions.toArray(new PathPermission[permissions.size()]);
    232       info.readPermission = data.getReadPermission();
    233       info.writePermission = data.getWritePermission();
    234       info.grantUriPermissions = data.getGrantUriPermissions();
    235       info.enabled = data.isEnabled();
    236       pkg.providers.add(createProvider(pkg, info));
    237     }
    238 
    239     for (BroadcastReceiverData data : androidManifest.getBroadcastReceivers()) {
    240       ActivityInfo info = new ActivityInfo();
    241       populateComponentInfo(info, pkg, data);
    242       info.permission = data.getPermission();
    243       info.exported = data.isExported();
    244       info.enabled = data.isEnabled();
    245       Activity receiver = createActivity(pkg, info);
    246       for (IntentFilterData intentFilterData : data.getIntentFilters()) {
    247         ActivityIntentInfo outInfo = new ActivityIntentInfo(receiver);
    248         populateIntentInfo(intentFilterData, outInfo);
    249         receiver.intents.add(outInfo);
    250       }
    251       pkg.receivers.add(receiver);
    252     }
    253 
    254     for (ServiceData data : androidManifest.getServices()) {
    255       ServiceInfo info = new ServiceInfo();
    256       populateComponentInfo(info, pkg, data);
    257       info.permission = data.getPermission();
    258       info.exported = data.isExported();
    259       info.enabled = data.isEnabled();
    260 
    261       Service service = createService(pkg, info);
    262       for (IntentFilterData intentFilterData : data.getIntentFilters()) {
    263         ServiceIntentInfo outInfo = new ServiceIntentInfo(service);
    264         populateIntentInfo(intentFilterData, outInfo);
    265         service.intents.add(outInfo);
    266       }
    267       pkg.services.add(service);
    268     }
    269 
    270     String codePath = RuntimeEnvironment.getTempDirectory()
    271         .createIfNotExists(pkg.packageName + "-codePath")
    272         .toAbsolutePath()
    273         .toString();
    274     if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) {
    275       pkg.codePath = codePath;
    276     } else {
    277       ReflectionHelpers.setField(Package.class, pkg, "mPath", codePath);
    278     }
    279 
    280     return pkg;
    281   }
    282 
    283   private static PathPermission createPathPermission(PathPermissionData data) {
    284     if (!Strings.isNullOrEmpty(data.pathPattern)) {
    285       return new PathPermission(
    286           data.pathPattern, PATTERN_SIMPLE_GLOB, data.readPermission, data.writePermission);
    287     } else if (!Strings.isNullOrEmpty(data.path)) {
    288       return new PathPermission(
    289           data.path, PATTERN_LITERAL, data.readPermission, data.writePermission);
    290     } else if (!Strings.isNullOrEmpty(data.pathPrefix)) {
    291       return new PathPermission(
    292           data.pathPrefix, PATTERN_PREFIX, data.readPermission, data.writePermission);
    293     } else {
    294       throw new IllegalStateException("Permission without type");
    295     }
    296   }
    297 
    298   private static void populateComponentInfo(
    299       ComponentInfo outInfo, Package owner, PackageItemData itemData) {
    300     populatePackageItemInfo(outInfo, owner, itemData);
    301     outInfo.applicationInfo = owner.applicationInfo;
    302   }
    303 
    304   private static void populatePackageItemInfo(
    305       PackageItemInfo outInfo, Package owner, PackageItemData itemData) {
    306     outInfo.name = buildClassName(owner.packageName, itemData.getName());
    307     outInfo.packageName = owner.packageName;
    308     outInfo.metaData = metaDataToBundle(itemData.getMetaData().getValueMap());
    309   }
    310 
    311   private static List<Boolean> buildBooleanList(int size, boolean defaultVal) {
    312     Boolean[] barray = new Boolean[size];
    313     Arrays.fill(barray, defaultVal);
    314     return Arrays.asList(barray);
    315   }
    316 
    317   private static PackageParser.Provider createProvider(Package pkg, ProviderInfo info) {
    318     PackageParser.Provider provider =
    319         ReflectionHelpers.callConstructor(PackageParser.Provider.class);
    320     populateComponent(pkg, info, provider);
    321     return provider;
    322   }
    323 
    324   private static Activity createActivity(Package pkg, ActivityInfo activityInfo) {
    325     Activity activity = ReflectionHelpers.callConstructor(Activity.class);
    326     populateComponent(pkg, activityInfo, activity);
    327     return activity;
    328   }
    329 
    330   private static Service createService(Package pkg, ServiceInfo info) {
    331     PackageParser.Service service = ReflectionHelpers.callConstructor(PackageParser.Service.class);
    332     populateComponent(pkg, info, service);
    333     return service;
    334   }
    335 
    336   private static void populateComponent(
    337       Package pkg, ComponentInfo info, PackageParser.Component component) {
    338     ReflectionHelpers.setField(component, "info", info);
    339     ReflectionHelpers.setField(component, "intents", new ArrayList<>());
    340     ReflectionHelpers.setField(component, "owner", pkg);
    341     ReflectionHelpers.setField(component, "className", info.name);
    342   }
    343 
    344   private static void populateIntentInfo(IntentFilterData intentFilterData, IntentInfo outInfo) {
    345     for (String action : intentFilterData.getActions()) {
    346       outInfo.addAction(action);
    347     }
    348     for (String category : intentFilterData.getCategories()) {
    349       outInfo.addCategory(category);
    350     }
    351     for (DataAuthority dataAuthority : intentFilterData.getAuthorities()) {
    352       outInfo.addDataAuthority(dataAuthority.getHost(), dataAuthority.getPort());
    353     }
    354     for (String mimeType : intentFilterData.getMimeTypes()) {
    355       try {
    356         outInfo.addDataType(mimeType);
    357       } catch (MalformedMimeTypeException e) {
    358         throw new RuntimeException(e);
    359       }
    360     }
    361     for (String scheme : intentFilterData.getSchemes()) {
    362       outInfo.addDataScheme(scheme);
    363     }
    364     for (String pathPattern : intentFilterData.getPathPatterns()) {
    365       outInfo.addDataPath(pathPattern, PATTERN_SIMPLE_GLOB);
    366     }
    367     for (String pathPattern : intentFilterData.getPathPrefixes()) {
    368       outInfo.addDataPath(pathPattern, PATTERN_PREFIX);
    369     }
    370     for (String pathPattern : intentFilterData.getPaths()) {
    371       outInfo.addDataPath(pathPattern, PATTERN_LITERAL);
    372     }
    373   }
    374 
    375   private static int getConfigChanges(ActivityData activityData) {
    376     String s = activityData.getConfigChanges();
    377 
    378     int res = 0;
    379 
    380     // quick sanity check.
    381     if (s == null || "".equals(s)) {
    382       return res;
    383     }
    384 
    385     String[] pieces = s.split("\\|", 0);
    386 
    387     for (String s1 : pieces) {
    388       s1 = s1.trim();
    389 
    390       for (Pair<String, Integer> pair : CONFIG_OPTIONS) {
    391         if (s1.equals(pair.first)) {
    392           res |= pair.second;
    393           break;
    394         }
    395       }
    396     }
    397 
    398     // Matches platform behavior
    399     if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.O) {
    400       res |= ActivityInfo.CONFIG_MNC;
    401       res |= ActivityInfo.CONFIG_MCC;
    402     }
    403 
    404     return res;
    405   }
    406 
    407   private static int decodeFlags(Map<String, String> applicationAttributes) {
    408     int applicationFlags = 0;
    409     for (Pair<String, Integer> pair : APPLICATION_FLAGS) {
    410       if ("true".equals(applicationAttributes.get(pair.first))) {
    411         applicationFlags |= pair.second;
    412       }
    413     }
    414     return applicationFlags;
    415   }
    416 
    417   private static PermissionInfo createPermissionInfo(Package owner, PermissionItemData itemData) {
    418     PermissionInfo permissionInfo = new PermissionInfo();
    419     populatePackageItemInfo(permissionInfo, owner, itemData);
    420 
    421     permissionInfo.group = itemData.getPermissionGroup();
    422     permissionInfo.protectionLevel = decodeProtectionLevel(itemData.getProtectionLevel());
    423     permissionInfo.metaData = metaDataToBundle(itemData.getMetaData().getValueMap());
    424 
    425     String descriptionRef = itemData.getDescription();
    426     if (descriptionRef != null) {
    427       ResName descResName =
    428           AttributeResource.getResourceReference(descriptionRef, owner.packageName, "string");
    429       permissionInfo.descriptionRes =
    430           RuntimeEnvironment.getAppResourceTable().getResourceId(descResName);
    431     }
    432 
    433     String labelRefOrString = itemData.getLabel();
    434     if (labelRefOrString != null) {
    435       if (AttributeResource.isResourceReference(labelRefOrString)) {
    436         ResName labelResName =
    437             AttributeResource.getResourceReference(labelRefOrString, owner.packageName, "string");
    438         permissionInfo.labelRes =
    439             RuntimeEnvironment.getAppResourceTable().getResourceId(labelResName);
    440       } else {
    441         permissionInfo.nonLocalizedLabel = labelRefOrString;
    442       }
    443     }
    444 
    445     return permissionInfo;
    446   }
    447 
    448   private static PermissionGroupInfo createPermissionGroupInfo(Package owner,
    449       PermissionGroupItemData itemData) {
    450     PermissionGroupInfo permissionGroupInfo = new PermissionGroupInfo();
    451     populatePackageItemInfo(permissionGroupInfo, owner, itemData);
    452 
    453     permissionGroupInfo.metaData = metaDataToBundle(itemData.getMetaData().getValueMap());
    454 
    455     String descriptionRef = itemData.getDescription();
    456     if (descriptionRef != null) {
    457       ResName descResName =
    458           AttributeResource.getResourceReference(descriptionRef, owner.packageName, "string");
    459       permissionGroupInfo.descriptionRes =
    460           RuntimeEnvironment.getAppResourceTable().getResourceId(descResName);
    461     }
    462 
    463     String labelRefOrString = itemData.getLabel();
    464     if (labelRefOrString != null) {
    465       if (AttributeResource.isResourceReference(labelRefOrString)) {
    466         ResName labelResName =
    467             AttributeResource.getResourceReference(labelRefOrString, owner.packageName, "string");
    468         permissionGroupInfo.labelRes =
    469             RuntimeEnvironment.getAppResourceTable().getResourceId(labelResName);
    470       } else {
    471         permissionGroupInfo.nonLocalizedLabel = labelRefOrString;
    472       }
    473     }
    474 
    475     return permissionGroupInfo;
    476   }
    477 
    478   private static int decodeProtectionLevel(String protectionLevel) {
    479     if (protectionLevel == null) {
    480       return PermissionInfo.PROTECTION_NORMAL;
    481     }
    482 
    483     int permissions = PermissionInfo.PROTECTION_NORMAL;
    484     String[] levels = protectionLevel.split("\\|", 0);
    485 
    486     for (String level : levels) {
    487       switch (level) {
    488         case "normal":
    489           permissions |= PermissionInfo.PROTECTION_NORMAL;
    490           break;
    491         case "dangerous":
    492           permissions |= PermissionInfo.PROTECTION_DANGEROUS;
    493           break;
    494         case "signature":
    495           permissions |= PermissionInfo.PROTECTION_SIGNATURE;
    496           break;
    497         case "signatureOrSystem":
    498           permissions |= PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM;
    499           break;
    500         case "privileged":
    501           permissions |= PermissionInfo.PROTECTION_FLAG_PRIVILEGED;
    502           break;
    503         case "system":
    504           permissions |= PermissionInfo.PROTECTION_FLAG_SYSTEM;
    505           break;
    506         case "development":
    507           permissions |= PermissionInfo.PROTECTION_FLAG_DEVELOPMENT;
    508           break;
    509         case "appop":
    510           permissions |= PermissionInfo.PROTECTION_FLAG_APPOP;
    511           break;
    512         case "pre23":
    513           permissions |= PermissionInfo.PROTECTION_FLAG_PRE23;
    514           break;
    515         case "installer":
    516           permissions |= PermissionInfo.PROTECTION_FLAG_INSTALLER;
    517           break;
    518         case "verifier":
    519           permissions |= PermissionInfo.PROTECTION_FLAG_VERIFIER;
    520           break;
    521         case "preinstalled":
    522           permissions |= PermissionInfo.PROTECTION_FLAG_PREINSTALLED;
    523           break;
    524         case "setup":
    525           permissions |= PermissionInfo.PROTECTION_FLAG_SETUP;
    526           break;
    527         case "instant":
    528           permissions |= PermissionInfo.PROTECTION_FLAG_INSTANT;
    529           break;
    530         case "runtime":
    531           permissions |= PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY;
    532           break;
    533         case "oem":
    534           permissions |= PermissionInfo.PROTECTION_FLAG_OEM;
    535           break;
    536         case "vendorPrivileged":
    537           permissions |= PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED;
    538           break;
    539         case "textClassifier":
    540           permissions |= PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER;
    541           break;
    542         default:
    543           throw new IllegalArgumentException("unknown protection level " + protectionLevel);
    544       }
    545     }
    546     return permissions;
    547   }
    548 
    549   /**
    550    * Goes through the meta data and puts each value in to a bundle as the correct type.
    551    *
    552    * <p>Note that this will convert resource identifiers specified via the value attribute as well.
    553    *
    554    * @param meta Meta data to put in to a bundle
    555    * @return bundle containing the meta data
    556    */
    557   private static Bundle metaDataToBundle(Map<String, Object> meta) {
    558     if (meta.size() == 0) {
    559       return null;
    560     }
    561 
    562     Bundle bundle = new Bundle();
    563 
    564     for (Map.Entry<String, Object> entry : meta.entrySet()) {
    565       String key = entry.getKey();
    566       Object value = entry.getValue();
    567       if (Boolean.class.isInstance(value)) {
    568         bundle.putBoolean(key, (Boolean) value);
    569       } else if (Float.class.isInstance(value)) {
    570         bundle.putFloat(key, (Float) value);
    571       } else if (Integer.class.isInstance(value)) {
    572         bundle.putInt(key, (Integer) value);
    573       } else {
    574         bundle.putString(key, value == null ? null : value.toString());
    575       }
    576     }
    577     return bundle;
    578   }
    579 
    580   private static String buildClassName(String pkg, String cls) {
    581     if (Strings.isNullOrEmpty(cls)) {
    582       throw new IllegalArgumentException("Empty class name in package " + pkg);
    583     }
    584     char c = cls.charAt(0);
    585     if (c == '.') {
    586       return (pkg + cls).intern();
    587     }
    588     if (cls.indexOf('.') < 0) {
    589       StringBuilder b = new StringBuilder(pkg);
    590       b.append('.');
    591       b.append(cls);
    592       return b.toString();
    593     }
    594     return cls;
    595     // TODO: consider reenabling this for stricter platform-complaint checking
    596     // if (c >= 'a' && c <= 'z') {
    597     // return cls;
    598     // }
    599     // throw new IllegalArgumentException("Bad class name " + cls + " in package " + pkg);
    600   }
    601 }
    602