diff --git a/api/current.txt b/api/current.txt index 3c0c64df89ba9..0337e11a3c79b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1376,6 +1376,7 @@ package android { field public static final int valueType = 16843488; // 0x10102e0 field public static final int variablePadding = 16843157; // 0x1010195 field public static final int vendor = 16843751; // 0x10103e7 + field public static final int version = 16844058; // 0x101051a field public static final int versionCode = 16843291; // 0x101021b field public static final int versionName = 16843292; // 0x101021c field public static final int verticalCorrection = 16843322; // 0x101023a @@ -9400,6 +9401,7 @@ package android.content.pm { field public int flags; field public java.lang.String name; field public int reqGlEsVersion; + field public int version; } public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { @@ -9678,6 +9680,7 @@ package android.content.pm { method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract boolean hasSystemFeature(java.lang.String); + method public abstract boolean hasSystemFeature(java.lang.String, int); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract java.util.List queryBroadcastReceivers(android.content.Intent, int); @@ -37789,6 +37792,7 @@ package android.test.mock { method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public boolean hasSystemFeature(java.lang.String); + method public boolean hasSystemFeature(java.lang.String, int); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public java.util.List queryBroadcastReceivers(android.content.Intent, int); diff --git a/api/system-current.txt b/api/system-current.txt index 335557b4baf9a..266900f917e97 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1475,6 +1475,7 @@ package android { field public static final int valueType = 16843488; // 0x10102e0 field public static final int variablePadding = 16843157; // 0x1010195 field public static final int vendor = 16843751; // 0x10103e7 + field public static final int version = 16844058; // 0x101051a field public static final int versionCode = 16843291; // 0x101021b field public static final int versionName = 16843292; // 0x101021c field public static final int verticalCorrection = 16843322; // 0x101023a @@ -9745,6 +9746,7 @@ package android.content.pm { field public int flags; field public java.lang.String name; field public int reqGlEsVersion; + field public int version; } public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { @@ -10027,6 +10029,7 @@ package android.content.pm { method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public abstract boolean hasSystemFeature(java.lang.String); + method public abstract boolean hasSystemFeature(java.lang.String, int); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract java.util.List queryBroadcastReceivers(android.content.Intent, int); @@ -40538,6 +40541,7 @@ package android.test.mock { method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public boolean hasSystemFeature(java.lang.String); + method public boolean hasSystemFeature(java.lang.String, int); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public java.util.List queryBroadcastReceivers(android.content.Intent, int); diff --git a/api/test-current.txt b/api/test-current.txt index 6bd4887582edc..15b1e7884cf50 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1376,6 +1376,7 @@ package android { field public static final int valueType = 16843488; // 0x10102e0 field public static final int variablePadding = 16843157; // 0x1010195 field public static final int vendor = 16843751; // 0x10103e7 + field public static final int version = 16844058; // 0x101051a field public static final int versionCode = 16843291; // 0x101021b field public static final int versionName = 16843292; // 0x101021c field public static final int verticalCorrection = 16843322; // 0x101023a @@ -9407,6 +9408,7 @@ package android.content.pm { field public int flags; field public java.lang.String name; field public int reqGlEsVersion; + field public int version; } public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { @@ -9686,6 +9688,7 @@ package android.content.pm { method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract boolean hasSystemFeature(java.lang.String); + method public abstract boolean hasSystemFeature(java.lang.String, int); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract java.util.List queryBroadcastReceivers(android.content.Intent, int); @@ -37806,6 +37809,7 @@ package android.test.mock { method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public boolean hasSystemFeature(java.lang.String); + method public boolean hasSystemFeature(java.lang.String, int); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public java.util.List queryBroadcastReceivers(android.content.Intent, int); diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java index e0f09ee2c6666..8e9791f8b731f 100644 --- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java +++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java @@ -58,7 +58,7 @@ public class NfcCommand extends Svc.Command { IPackageManager pm = IPackageManager.Stub.asInterface( ServiceManager.getService("package")); try { - if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { + if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0)) { INfcAdapter nfc = INfcAdapter.Stub .asInterface(ServiceManager.getService(Context.NFC_SERVICE)); try { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index df4b7d1eb50d8..7e50518cb3e12 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -450,8 +450,13 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean hasSystemFeature(String name) { + return hasSystemFeature(name, 0); + } + + @Override + public boolean hasSystemFeature(String name, int version) { try { - return mPM.hasSystemFeature(name); + return mPM.hasSystemFeature(name, version); } catch (RemoteException e) { throw new RuntimeException("Package manager has died", e); } diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java index 79fa32791a31f..7671f72cbeacc 100644 --- a/core/java/android/content/pm/FeatureInfo.java +++ b/core/java/android/content/pm/FeatureInfo.java @@ -20,9 +20,18 @@ import android.os.Parcel; import android.os.Parcelable; /** - * A single feature that can be requested by an application. This corresponds - * to information collected from the - * AndroidManifest.xml's {@code } tag. + * Definition of a single optional hardware or software feature of an Android + * device. + *

+ * This object is used to represent both features supported by a device and + * features requested by an app. Apps can request that certain features be + * available as a prerequisite to being installed through the + * {@code uses-feature} tag in their manifests. + *

+ * Starting in {@link android.os.Build.VERSION_CODES#N}, features can have a + * version, which must always be backwards compatible. That is, a device + * claiming to support version 3 of a specific feature must support apps + * requesting version 1 of that feature. */ public class FeatureInfo implements Parcelable { /** @@ -31,7 +40,17 @@ public class FeatureInfo implements Parcelable { * in {@link #reqGlEsVersion}. */ public String name; - + + /** + * If this object represents a feature supported by a device, this is the + * maximum version of this feature supported by the device. The device + * implicitly supports all older versions of this feature. + *

+ * If this object represents a feature requested by an app, this is the + * minimum version of the feature required by the app. + */ + public int version; + /** * Default value for {@link #reqGlEsVersion}; */ @@ -59,15 +78,17 @@ public class FeatureInfo implements Parcelable { public FeatureInfo(FeatureInfo orig) { name = orig.name; + version = orig.version; reqGlEsVersion = orig.reqGlEsVersion; flags = orig.flags; } + @Override public String toString() { if (name != null) { return "FeatureInfo{" + Integer.toHexString(System.identityHashCode(this)) - + " " + name + " fl=0x" + Integer.toHexString(flags) + "}"; + + " " + name + " v=" + version + " fl=0x" + Integer.toHexString(flags) + "}"; } else { return "FeatureInfo{" + Integer.toHexString(System.identityHashCode(this)) @@ -76,21 +97,25 @@ public class FeatureInfo implements Parcelable { } } + @Override public int describeContents() { return 0; } + @Override public void writeToParcel(Parcel dest, int parcelableFlags) { dest.writeString(name); + dest.writeInt(version); dest.writeInt(reqGlEsVersion); dest.writeInt(flags); } - public static final Creator CREATOR = - new Creator() { + public static final Creator CREATOR = new Creator() { + @Override public FeatureInfo createFromParcel(Parcel source) { return new FeatureInfo(source); } + @Override public FeatureInfo[] newArray(int size) { return new FeatureInfo[size]; } @@ -98,6 +123,7 @@ public class FeatureInfo implements Parcelable { private FeatureInfo(Parcel source) { name = source.readString(); + version = source.readInt(); reqGlEsVersion = source.readInt(); flags = source.readInt(); } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 386385790e49e..c71a60353e1ad 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -416,7 +416,7 @@ interface IPackageManager { */ FeatureInfo[] getSystemAvailableFeatures(); - boolean hasSystemFeature(String name); + boolean hasSystemFeature(String name, int version); void enterSafeMode(); boolean isSafeMode(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index bf0d4ded17a9e..36b902c3e481a 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3405,14 +3405,26 @@ public abstract class PackageManager { public abstract FeatureInfo[] getSystemAvailableFeatures(); /** - * Check whether the given feature name is one of the available - * features as returned by {@link #getSystemAvailableFeatures()}. + * Check whether the given feature name is one of the available features as + * returned by {@link #getSystemAvailableFeatures()}. This tests for the + * presence of any version of the given feature name; use + * {@link #hasSystemFeature(String, int)} to check for a minimum version. * - * @return Returns true if the devices supports the feature, else - * false. + * @return Returns true if the devices supports the feature, else false. */ public abstract boolean hasSystemFeature(String name); + /** + * Check whether the given feature name and version is one of the available + * features as returned by {@link #getSystemAvailableFeatures()}. Since + * features are defined to always be backwards compatible, this returns true + * if the available feature version is greater than or equal to the + * requested version. + * + * @return Returns true if the devices supports the feature, else false. + */ + public abstract boolean hasSystemFeature(String name, int version); + /** * Determine the best action to perform for a given Intent. This is how * {@link Intent#resolveActivity} finds an activity if a class has not diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 5ae8d4cf0ce41..1ee19de282acf 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2127,6 +2127,8 @@ public class PackageParser { // that may change. fi.name = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestUsesFeature_name); + fi.version = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0); if (fi.name == null) { fi.reqGlEsVersion = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index acd780d9ecad3..6f911ceb4bedd 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -414,7 +414,7 @@ public final class NfcAdapter { return false; } try { - return pm.hasSystemFeature(PackageManager.FEATURE_NFC); + return pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0); } catch (RemoteException e) { Log.e(TAG, "Package manager query failed, assuming no NFC feature", e); return false; diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 23d05bda36333..b49288e6e59ef 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -156,7 +156,7 @@ public final class CardEmulation { throw new UnsupportedOperationException(); } try { - if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) { + if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) { Log.e(TAG, "This device does not support card emulation"); throw new UnsupportedOperationException(); } diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java index d61ac02eb98e5..42ccf20a584a5 100644 --- a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java +++ b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java @@ -77,7 +77,7 @@ public final class NfcFCardEmulation { throw new UnsupportedOperationException(); } try { - if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)) { + if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 0)) { Log.e(TAG, "This device does not support NFC-F card emulation"); throw new UnsupportedOperationException(); } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 1496d0926dc6d..f91bcd0bdeeaa 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1425,22 +1425,24 @@ - + + + + - - - +