summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java108
-rw-r--r--core/res/res/values/attrs_manifest.xml16
2 files changed, 109 insertions, 15 deletions
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 9197020e1fce..b936c6323a80 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1080,14 +1080,57 @@ public class ParsingPackageUtils {
}
}
- final String requiredFeature = sa.getNonConfigurationString(
- R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+ final ArraySet<String> requiredFeatures = new ArraySet<>();
+ String feature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature,
+ 0);
+ if (feature != null) {
+ requiredFeatures.add(feature);
+ }
- final String requiredNotfeature = sa.getNonConfigurationString(
- R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
+ final ArraySet<String> requiredNotFeatures = new ArraySet<>();
+ feature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable
+ .AndroidManifestUsesPermission_requiredNotFeature,
0);
+ if (feature != null) {
+ requiredNotFeatures.add(feature);
+ }
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ final ParseResult<?> result;
+ switch (parser.getName()) {
+ case "required-feature":
+ result = parseRequiredFeature(input, res, parser);
+ if (result.isSuccess()) {
+ requiredFeatures.add((String) result.getResult());
+ }
+ break;
+
+ case "required-not-feature":
+ result = parseRequiredNotFeature(input, res, parser);
+ if (result.isSuccess()) {
+ requiredNotFeatures.add((String) result.getResult());
+ }
+ break;
- XmlUtils.skipCurrentTag(parser);
+ default:
+ result = ParsingUtils.unknownTag("<uses-permission>", pkg, parser, input);
+ break;
+ }
+
+ if (result.isError()) {
+ return input.error(result);
+ }
+ }
// Can only succeed from here on out
ParseResult<ParsingPackage> success = input.success(pkg);
@@ -1100,17 +1143,22 @@ public class ParsingPackageUtils {
return success;
}
- // Only allow requesting this permission if the platform supports the given feature.
- if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(
- requiredFeature)) {
- return success;
- }
+ if (mCallback != null) {
+ // Only allow requesting this permission if the platform supports all of the
+ // "required-feature"s.
+ for (int i = requiredFeatures.size() - 1; i >= 0; i--) {
+ if (!mCallback.hasFeature(requiredFeatures.valueAt(i))) {
+ return success;
+ }
+ }
- // Only allow requesting this permission if the platform doesn't support the given
- // feature.
- if (requiredNotfeature != null && mCallback != null
- && mCallback.hasFeature(requiredNotfeature)) {
- return success;
+ // Only allow requesting this permission if the platform does not supports any of
+ // the "required-not-feature"s.
+ for (int i = requiredNotFeatures.size() - 1; i >= 0; i--) {
+ if (mCallback.hasFeature(requiredNotFeatures.valueAt(i))) {
+ return success;
+ }
+ }
}
if (!pkg.getRequestedPermissions().contains(name)) {
@@ -1127,6 +1175,36 @@ public class ParsingPackageUtils {
}
}
+ private ParseResult<String> parseRequiredFeature(ParseInput input, Resources res,
+ AttributeSet attrs) {
+ final TypedArray sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestRequiredFeature);
+ try {
+ final String featureName = sa.getString(
+ R.styleable.AndroidManifestRequiredFeature_name);
+ return TextUtils.isEmpty(featureName)
+ ? input.error("Feature name is missing from <required-feature> tag.")
+ : input.success(featureName);
+ } finally {
+ sa.recycle();
+ }
+ }
+
+ private ParseResult<String> parseRequiredNotFeature(ParseInput input, Resources res,
+ AttributeSet attrs) {
+ final TypedArray sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestRequiredNotFeature);
+ try {
+ final String featureName = sa.getString(
+ R.styleable.AndroidManifestRequiredNotFeature_name);
+ return TextUtils.isEmpty(featureName)
+ ? input.error("Feature name is missing from <required-not-feature> tag.")
+ : input.success(featureName);
+ } finally {
+ sa.recycle();
+ }
+ }
+
private static ParseResult<ParsingPackage> parseUsesConfiguration(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser) {
ConfigurationInfo cPref = new ConfigurationInfo();
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 96ebc127e9ba..25c64a9f8781 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2016,6 +2016,22 @@
<attr name="requiredNotFeature" format="string" />
</declare-styleable>
+ <!-- <code>required-feature</code> and <code>required-not-feature</code> elements inside
+ <code>uses-permission<code/> can be used to request the permission based on the fact
+ whether the system supports or does not support certain features.
+ If multiple <code>required-feature</code> and/or <code>required-not-feature</code> elements
+ are present, the permission will be “requested” only if the system supports all of the
+ listed "required-features" and does not support any of the "required-not-features".
+ -->
+ <declare-styleable name="AndroidManifestRequiredFeature">
+ <!-- The name of the feature. -->
+ <attr name="name" />
+ </declare-styleable>
+ <declare-styleable name="AndroidManifestRequiredNotFeature">
+ <!-- The name of the feature. -->
+ <attr name="name" />
+ </declare-styleable>
+
<!-- The <code>uses-configuration</code> tag specifies
a specific hardware configuration value used by the application.
For example an application might specify that it requires