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