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.PatternMatcher.PATTERN_LITERAL; 19 import static android.os.PatternMatcher.PATTERN_PREFIX; 20 import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB; 21 import static java.util.Arrays.asList; 22 23 import android.content.IntentFilter.MalformedMimeTypeException; 24 import android.content.pm.ActivityInfo; 25 import android.content.pm.ComponentInfo; 26 import android.content.pm.PackageInfo; 27 import android.content.pm.PackageItemInfo; 28 import android.content.pm.PackageParser; 29 import android.content.pm.PackageParser.Activity; 30 import android.content.pm.PackageParser.ActivityIntentInfo; 31 import android.content.pm.PackageParser.IntentInfo; 32 import android.content.pm.PackageParser.Package; 33 import android.content.pm.PackageParser.Permission; 34 import android.content.pm.PackageParser.PermissionGroup; 35 import android.content.pm.PackageParser.Service; 36 import android.content.pm.PackageParser.ServiceIntentInfo; 37 import android.content.pm.PathPermission; 38 import android.content.pm.PermissionGroupInfo; 39 import android.content.pm.PermissionInfo; 40 import android.content.pm.ProviderInfo; 41 import android.content.pm.ServiceInfo; 42 import android.os.Build; 43 import android.os.Build.VERSION_CODES; 44 import android.os.Bundle; 45 import android.os.Process; 46 import android.util.Pair; 47 import com.google.common.base.Strings; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.List; 51 import java.util.Map; 52 import org.robolectric.RuntimeEnvironment; 53 import org.robolectric.manifest.ActivityData; 54 import org.robolectric.manifest.AndroidManifest; 55 import org.robolectric.manifest.BroadcastReceiverData; 56 import org.robolectric.manifest.ContentProviderData; 57 import org.robolectric.manifest.IntentFilterData; 58 import org.robolectric.manifest.IntentFilterData.DataAuthority; 59 import org.robolectric.manifest.PackageItemData; 60 import org.robolectric.manifest.PathPermissionData; 61 import org.robolectric.manifest.PermissionGroupItemData; 62 import org.robolectric.manifest.PermissionItemData; 63 import org.robolectric.manifest.ServiceData; 64 import org.robolectric.res.AttributeResource; 65 import org.robolectric.res.ResName; 66 import org.robolectric.util.ReflectionHelpers; 67 68 /** Creates a {@link PackageInfo} from a {@link AndroidManifest} */ 69 @SuppressWarnings("NewApi") 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 createPackage(AndroidManifest androidManifest)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 pkg.codePath = codePath; 275 return pkg; 276 } 277 createPathPermission(PathPermissionData data)278 private static PathPermission createPathPermission(PathPermissionData data) { 279 if (!Strings.isNullOrEmpty(data.pathPattern)) { 280 return new PathPermission( 281 data.pathPattern, PATTERN_SIMPLE_GLOB, data.readPermission, data.writePermission); 282 } else if (!Strings.isNullOrEmpty(data.path)) { 283 return new PathPermission( 284 data.path, PATTERN_LITERAL, data.readPermission, data.writePermission); 285 } else if (!Strings.isNullOrEmpty(data.pathPrefix)) { 286 return new PathPermission( 287 data.pathPrefix, PATTERN_PREFIX, data.readPermission, data.writePermission); 288 } else { 289 throw new IllegalStateException("Permission without type"); 290 } 291 } 292 populateComponentInfo( ComponentInfo outInfo, Package owner, PackageItemData itemData)293 private static void populateComponentInfo( 294 ComponentInfo outInfo, Package owner, PackageItemData itemData) { 295 populatePackageItemInfo(outInfo, owner, itemData); 296 outInfo.applicationInfo = owner.applicationInfo; 297 } 298 populatePackageItemInfo( PackageItemInfo outInfo, Package owner, PackageItemData itemData)299 private static void populatePackageItemInfo( 300 PackageItemInfo outInfo, Package owner, PackageItemData itemData) { 301 outInfo.name = buildClassName(owner.packageName, itemData.getName()); 302 outInfo.packageName = owner.packageName; 303 outInfo.metaData = metaDataToBundle(itemData.getMetaData().getValueMap()); 304 } 305 buildBooleanList(int size, boolean defaultVal)306 private static List<Boolean> buildBooleanList(int size, boolean defaultVal) { 307 Boolean[] barray = new Boolean[size]; 308 Arrays.fill(barray, defaultVal); 309 return Arrays.asList(barray); 310 } 311 createProvider(Package pkg, ProviderInfo info)312 private static PackageParser.Provider createProvider(Package pkg, ProviderInfo info) { 313 PackageParser.Provider provider = 314 ReflectionHelpers.callConstructor(PackageParser.Provider.class); 315 populateComponent(pkg, info, provider); 316 return provider; 317 } 318 createActivity(Package pkg, ActivityInfo activityInfo)319 private static Activity createActivity(Package pkg, ActivityInfo activityInfo) { 320 Activity activity = ReflectionHelpers.callConstructor(Activity.class); 321 populateComponent(pkg, activityInfo, activity); 322 return activity; 323 } 324 createService(Package pkg, ServiceInfo info)325 private static Service createService(Package pkg, ServiceInfo info) { 326 PackageParser.Service service = ReflectionHelpers.callConstructor(PackageParser.Service.class); 327 populateComponent(pkg, info, service); 328 return service; 329 } 330 populateComponent( Package pkg, ComponentInfo info, PackageParser.Component component)331 private static void populateComponent( 332 Package pkg, ComponentInfo info, PackageParser.Component component) { 333 ReflectionHelpers.setField(component, "info", info); 334 ReflectionHelpers.setField(component, "intents", new ArrayList<>()); 335 ReflectionHelpers.setField(component, "owner", pkg); 336 ReflectionHelpers.setField(component, "className", info.name); 337 } 338 populateIntentInfo(IntentFilterData intentFilterData, IntentInfo outInfo)339 private static void populateIntentInfo(IntentFilterData intentFilterData, IntentInfo outInfo) { 340 for (String action : intentFilterData.getActions()) { 341 outInfo.addAction(action); 342 } 343 for (String category : intentFilterData.getCategories()) { 344 outInfo.addCategory(category); 345 } 346 for (DataAuthority dataAuthority : intentFilterData.getAuthorities()) { 347 outInfo.addDataAuthority(dataAuthority.getHost(), dataAuthority.getPort()); 348 } 349 for (String mimeType : intentFilterData.getMimeTypes()) { 350 try { 351 outInfo.addDataType(mimeType); 352 } catch (MalformedMimeTypeException e) { 353 throw new RuntimeException(e); 354 } 355 } 356 for (String scheme : intentFilterData.getSchemes()) { 357 outInfo.addDataScheme(scheme); 358 } 359 for (String pathPattern : intentFilterData.getPathPatterns()) { 360 outInfo.addDataPath(pathPattern, PATTERN_SIMPLE_GLOB); 361 } 362 for (String pathPattern : intentFilterData.getPathPrefixes()) { 363 outInfo.addDataPath(pathPattern, PATTERN_PREFIX); 364 } 365 for (String pathPattern : intentFilterData.getPaths()) { 366 outInfo.addDataPath(pathPattern, PATTERN_LITERAL); 367 } 368 } 369 getConfigChanges(ActivityData activityData)370 private static int getConfigChanges(ActivityData activityData) { 371 String s = activityData.getConfigChanges(); 372 373 int res = 0; 374 375 // quick sanity check. 376 if (s == null || "".equals(s)) { 377 return res; 378 } 379 380 String[] pieces = s.split("\\|", 0); 381 382 for (String s1 : pieces) { 383 s1 = s1.trim(); 384 385 for (Pair<String, Integer> pair : CONFIG_OPTIONS) { 386 if (s1.equals(pair.first)) { 387 res |= pair.second; 388 break; 389 } 390 } 391 } 392 393 // Matches platform behavior 394 if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.O) { 395 res |= ActivityInfo.CONFIG_MNC; 396 res |= ActivityInfo.CONFIG_MCC; 397 } 398 399 return res; 400 } 401 decodeFlags(Map<String, String> applicationAttributes)402 private static int decodeFlags(Map<String, String> applicationAttributes) { 403 int applicationFlags = 0; 404 for (Pair<String, Integer> pair : APPLICATION_FLAGS) { 405 if ("true".equals(applicationAttributes.get(pair.first))) { 406 applicationFlags |= pair.second; 407 } 408 } 409 return applicationFlags; 410 } 411 createPermissionInfo(Package owner, PermissionItemData itemData)412 private static PermissionInfo createPermissionInfo(Package owner, PermissionItemData itemData) { 413 PermissionInfo permissionInfo = new PermissionInfo(); 414 populatePackageItemInfo(permissionInfo, owner, itemData); 415 416 permissionInfo.group = itemData.getPermissionGroup(); 417 permissionInfo.protectionLevel = decodeProtectionLevel(itemData.getProtectionLevel()); 418 permissionInfo.metaData = metaDataToBundle(itemData.getMetaData().getValueMap()); 419 420 String descriptionRef = itemData.getDescription(); 421 if (descriptionRef != null) { 422 ResName descResName = 423 AttributeResource.getResourceReference(descriptionRef, owner.packageName, "string"); 424 permissionInfo.descriptionRes = 425 RuntimeEnvironment.getAppResourceTable().getResourceId(descResName); 426 } 427 428 String labelRefOrString = itemData.getLabel(); 429 if (labelRefOrString != null) { 430 if (AttributeResource.isResourceReference(labelRefOrString)) { 431 ResName labelResName = 432 AttributeResource.getResourceReference(labelRefOrString, owner.packageName, "string"); 433 permissionInfo.labelRes = 434 RuntimeEnvironment.getAppResourceTable().getResourceId(labelResName); 435 } else { 436 permissionInfo.nonLocalizedLabel = labelRefOrString; 437 } 438 } 439 440 return permissionInfo; 441 } 442 createPermissionGroupInfo(Package owner, PermissionGroupItemData itemData)443 private static PermissionGroupInfo createPermissionGroupInfo(Package owner, 444 PermissionGroupItemData itemData) { 445 PermissionGroupInfo permissionGroupInfo = new PermissionGroupInfo(); 446 populatePackageItemInfo(permissionGroupInfo, owner, itemData); 447 448 permissionGroupInfo.metaData = metaDataToBundle(itemData.getMetaData().getValueMap()); 449 450 String descriptionRef = itemData.getDescription(); 451 if (descriptionRef != null) { 452 ResName descResName = 453 AttributeResource.getResourceReference(descriptionRef, owner.packageName, "string"); 454 permissionGroupInfo.descriptionRes = 455 RuntimeEnvironment.getAppResourceTable().getResourceId(descResName); 456 } 457 458 String labelRefOrString = itemData.getLabel(); 459 if (labelRefOrString != null) { 460 if (AttributeResource.isResourceReference(labelRefOrString)) { 461 ResName labelResName = 462 AttributeResource.getResourceReference(labelRefOrString, owner.packageName, "string"); 463 permissionGroupInfo.labelRes = 464 RuntimeEnvironment.getAppResourceTable().getResourceId(labelResName); 465 } else { 466 permissionGroupInfo.nonLocalizedLabel = labelRefOrString; 467 } 468 } 469 470 return permissionGroupInfo; 471 } 472 decodeProtectionLevel(String protectionLevel)473 private static int decodeProtectionLevel(String protectionLevel) { 474 if (protectionLevel == null) { 475 return PermissionInfo.PROTECTION_NORMAL; 476 } 477 478 int permissions = PermissionInfo.PROTECTION_NORMAL; 479 String[] levels = protectionLevel.split("\\|", 0); 480 481 for (String level : levels) { 482 switch (level) { 483 case "normal": 484 permissions |= PermissionInfo.PROTECTION_NORMAL; 485 break; 486 case "dangerous": 487 permissions |= PermissionInfo.PROTECTION_DANGEROUS; 488 break; 489 case "signature": 490 permissions |= PermissionInfo.PROTECTION_SIGNATURE; 491 break; 492 case "signatureOrSystem": 493 permissions |= PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM; 494 break; 495 case "privileged": 496 permissions |= PermissionInfo.PROTECTION_FLAG_PRIVILEGED; 497 break; 498 case "system": 499 permissions |= PermissionInfo.PROTECTION_FLAG_SYSTEM; 500 break; 501 case "development": 502 permissions |= PermissionInfo.PROTECTION_FLAG_DEVELOPMENT; 503 break; 504 case "appop": 505 permissions |= PermissionInfo.PROTECTION_FLAG_APPOP; 506 break; 507 case "pre23": 508 permissions |= PermissionInfo.PROTECTION_FLAG_PRE23; 509 break; 510 case "installer": 511 permissions |= PermissionInfo.PROTECTION_FLAG_INSTALLER; 512 break; 513 case "verifier": 514 permissions |= PermissionInfo.PROTECTION_FLAG_VERIFIER; 515 break; 516 case "preinstalled": 517 permissions |= PermissionInfo.PROTECTION_FLAG_PREINSTALLED; 518 break; 519 case "setup": 520 permissions |= PermissionInfo.PROTECTION_FLAG_SETUP; 521 break; 522 case "instant": 523 permissions |= PermissionInfo.PROTECTION_FLAG_INSTANT; 524 break; 525 case "runtime": 526 permissions |= PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY; 527 break; 528 case "oem": 529 permissions |= PermissionInfo.PROTECTION_FLAG_OEM; 530 break; 531 case "vendorPrivileged": 532 permissions |= PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED; 533 break; 534 case "textClassifier": 535 permissions |= PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER; 536 break; 537 default: 538 throw new IllegalArgumentException("unknown protection level " + protectionLevel); 539 } 540 } 541 return permissions; 542 } 543 544 /** 545 * Goes through the meta data and puts each value in to a bundle as the correct type. 546 * 547 * <p>Note that this will convert resource identifiers specified via the value attribute as well. 548 * 549 * @param meta Meta data to put in to a bundle 550 * @return bundle containing the meta data 551 */ metaDataToBundle(Map<String, Object> meta)552 private static Bundle metaDataToBundle(Map<String, Object> meta) { 553 if (meta.size() == 0) { 554 return null; 555 } 556 557 Bundle bundle = new Bundle(); 558 559 for (Map.Entry<String, Object> entry : meta.entrySet()) { 560 String key = entry.getKey(); 561 Object value = entry.getValue(); 562 if (Boolean.class.isInstance(value)) { 563 bundle.putBoolean(key, (Boolean) value); 564 } else if (Float.class.isInstance(value)) { 565 bundle.putFloat(key, (Float) value); 566 } else if (Integer.class.isInstance(value)) { 567 bundle.putInt(key, (Integer) value); 568 } else { 569 bundle.putString(key, value == null ? null : value.toString()); 570 } 571 } 572 return bundle; 573 } 574 buildClassName(String pkg, String cls)575 private static String buildClassName(String pkg, String cls) { 576 if (Strings.isNullOrEmpty(cls)) { 577 throw new IllegalArgumentException("Empty class name in package " + pkg); 578 } 579 char c = cls.charAt(0); 580 if (c == '.') { 581 return (pkg + cls).intern(); 582 } 583 if (cls.indexOf('.') < 0) { 584 StringBuilder b = new StringBuilder(pkg); 585 b.append('.'); 586 b.append(cls); 587 return b.toString(); 588 } 589 return cls; 590 // TODO: consider reenabling this for stricter platform-complaint checking 591 // if (c >= 'a' && c <= 'z') { 592 // return cls; 593 // } 594 // throw new IllegalArgumentException("Bad class name " + cls + " in package " + pkg); 595 } 596 } 597