summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml161
-rw-r--r--core/java/android/app/ApplicationContext.java10
-rwxr-xr-xcore/java/android/content/pm/ConfigurationInfo.java16
-rwxr-xr-xcore/java/android/content/pm/FeatureInfo.aidl19
-rw-r--r--core/java/android/content/pm/FeatureInfo.java101
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl7
-rw-r--r--core/java/android/content/pm/PackageInfo.java7
-rw-r--r--core/java/android/content/pm/PackageManager.java24
-rw-r--r--core/java/android/content/pm/PackageParser.java71
-rw-r--r--core/res/res/values/attrs_manifest.xml8
-rw-r--r--data/etc/android.hardware.camera.autofocus.xml21
-rw-r--r--services/java/com/android/server/PackageManagerService.java109
-rw-r--r--test-runner/android/test/mock/MockPackageManager.java6
-rw-r--r--tools/aapt/Command.cpp7
14 files changed, 527 insertions, 40 deletions
diff --git a/api/current.xml b/api/current.xml
index 96e1d2d..dcf0d84 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -37589,6 +37589,134 @@
>
</field>
</class>
+<class name="FeatureInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="FeatureInfo"
+ type="android.content.pm.FeatureInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="FeatureInfo"
+ type="android.content.pm.FeatureInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="orig" type="android.content.pm.FeatureInfo">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGlEsVersion"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="parcelableFlags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_REQUIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GL_ES_VERSION_UNDEFINED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="flags"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="name"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="reqGlEsVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="InstrumentationInfo"
extends="android.content.pm.PackageItemInfo"
abstract="false"
@@ -37850,6 +37978,17 @@
visibility="public"
>
</field>
+<field name="reqFeatures"
+ type="android.content.pm.FeatureInfo[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="requestedPermissions"
type="java.lang.String[]"
transient="false"
@@ -38719,6 +38858,17 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getSystemAvailableFeatures"
+ return="android.content.pm.FeatureInfo[]"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSystemSharedLibraryNames"
return="java.lang.String[]"
abstract="true"
@@ -122943,6 +123093,17 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getSystemAvailableFeatures"
+ return="android.content.pm.FeatureInfo[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSystemSharedLibraryNames"
return="java.lang.String[]"
abstract="false"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 7c0d1d3..487cfda 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -40,6 +40,7 @@ import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
@@ -1623,6 +1624,15 @@ class ApplicationContext extends Context {
}
@Override
+ public FeatureInfo[] getSystemAvailableFeatures() {
+ try {
+ return mPM.getSystemAvailableFeatures();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
public int checkPermission(String permName, String pkgName) {
try {
return mPM.checkPermission(permName, pkgName);
diff --git a/core/java/android/content/pm/ConfigurationInfo.java b/core/java/android/content/pm/ConfigurationInfo.java
index fb7a47f..8edd436 100755
--- a/core/java/android/content/pm/ConfigurationInfo.java
+++ b/core/java/android/content/pm/ConfigurationInfo.java
@@ -22,9 +22,9 @@ import android.os.Parcelable;
/**
* Information you can retrieve about hardware configuration preferences
* declared by an application. This corresponds to information collected from the
- * AndroidManifest.xml's &lt;uses-configuration&gt; and the &lt;uses-feature&gt;tags.
+ * AndroidManifest.xml's &lt;uses-configuration&gt; and &lt;uses-feature&gt; tags.
*/
-public class ConfigurationInfo implements Parcelable {
+public class ConfigurationInfo implements Parcelable {
/**
* The kind of touch screen attached to the device.
* One of: {@link android.content.res.Configuration#TOUCHSCREEN_NOTOUCH},
@@ -92,13 +92,13 @@ public class ConfigurationInfo implements Parcelable {
}
public String toString() {
- return "ApplicationHardwarePreferences{"
+ return "ConfigurationInfo{"
+ Integer.toHexString(System.identityHashCode(this))
- + ", touchscreen = " + reqTouchScreen + "}"
- + ", inputMethod = " + reqKeyboardType + "}"
- + ", navigation = " + reqNavigation + "}"
- + ", reqInputFeatures = " + reqInputFeatures + "}"
- + ", reqGlEsVersion = " + reqGlEsVersion + "}";
+ + " touchscreen = " + reqTouchScreen
+ + " inputMethod = " + reqKeyboardType
+ + " navigation = " + reqNavigation
+ + " reqInputFeatures = " + reqInputFeatures
+ + " reqGlEsVersion = " + reqGlEsVersion + "}";
}
public int describeContents() {
diff --git a/core/java/android/content/pm/FeatureInfo.aidl b/core/java/android/content/pm/FeatureInfo.aidl
new file mode 100755
index 0000000..d84a84c
--- /dev/null
+++ b/core/java/android/content/pm/FeatureInfo.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm;
+
+parcelable FeatureInfo;
diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java
new file mode 100644
index 0000000..57d61fd
--- /dev/null
+++ b/core/java/android/content/pm/FeatureInfo.java
@@ -0,0 +1,101 @@
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Parcelable.Creator;
+
+/**
+ * A single feature that can be requested by an application. This corresponds
+ * to information collected from the
+ * AndroidManifest.xml's &lt;uses-feature&gt; tag.
+ */
+public class FeatureInfo implements Parcelable {
+ /**
+ * The name of this feature, for example "android.hardware.camera". If
+ * this is null, then this is an OpenGL ES version feature as described
+ * in {@link #reqGlEsVersion}.
+ */
+ public String name;
+
+ /**
+ * Default value for {@link #reqGlEsVersion};
+ */
+ public static final int GL_ES_VERSION_UNDEFINED = 0;
+
+ /**
+ * The GLES version used by an application. The upper order 16 bits represent the
+ * major version and the lower order 16 bits the minor version. Only valid
+ * if {@link #name} is null.
+ */
+ public int reqGlEsVersion;
+
+ /**
+ * Set on {@link #flags} if this feature has been required by the application.
+ */
+ public static final int FLAG_REQUIRED = 0x0001;
+
+ /**
+ * Additional flags. May be zero or more of {@link #FLAG_REQUIRED}.
+ */
+ public int flags;
+
+ public FeatureInfo() {
+ }
+
+ public FeatureInfo(FeatureInfo orig) {
+ name = orig.name;
+ reqGlEsVersion = orig.reqGlEsVersion;
+ flags = orig.flags;
+ }
+
+ public String toString() {
+ if (name != null) {
+ return "FeatureInfo{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + name + " fl=0x" + Integer.toHexString(flags) + "}";
+ } else {
+ return "FeatureInfo{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " glEsVers=" + getGlEsVersion()
+ + " fl=0x" + Integer.toHexString(flags) + "}";
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeString(name);
+ dest.writeInt(reqGlEsVersion);
+ dest.writeInt(flags);
+ }
+
+ public static final Creator<FeatureInfo> CREATOR =
+ new Creator<FeatureInfo>() {
+ public FeatureInfo createFromParcel(Parcel source) {
+ return new FeatureInfo(source);
+ }
+ public FeatureInfo[] newArray(int size) {
+ return new FeatureInfo[size];
+ }
+ };
+
+ private FeatureInfo(Parcel source) {
+ name = source.readString();
+ reqGlEsVersion = source.readInt();
+ flags = source.readInt();
+ }
+
+ /**
+ * This method extracts the major and minor version of reqGLEsVersion attribute
+ * and returns it as a string. Say reqGlEsVersion value of 0x00010002 is returned
+ * as 1.2
+ * @return String representation of the reqGlEsVersion attribute
+ */
+ public String getGlEsVersion() {
+ int major = ((reqGlEsVersion & 0xffff0000) >> 16);
+ int minor = reqGlEsVersion & 0x0000ffff;
+ return String.valueOf(major)+"."+String.valueOf(minor);
+ }
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4fc4fb9..c322951 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDataObserver;
@@ -276,6 +277,12 @@ interface IPackageManager {
*/
String[] getSystemSharedLibraryNames();
+ /**
+ * Get a list of features that are available on the
+ * system.
+ */
+ FeatureInfo[] getSystemAvailableFeatures();
+
void enterSafeMode();
boolean isSafeMode();
void systemReady();
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index d9326f2..a8ce889 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -127,6 +127,11 @@ public class PackageInfo implements Parcelable {
*/
public ConfigurationInfo[] configPreferences;
+ /**
+ * The features that this application has said it requires.
+ */
+ public FeatureInfo[] reqFeatures;
+
public PackageInfo() {
}
@@ -162,6 +167,7 @@ public class PackageInfo implements Parcelable {
dest.writeStringArray(requestedPermissions);
dest.writeTypedArray(signatures, parcelableFlags);
dest.writeTypedArray(configPreferences, parcelableFlags);
+ dest.writeTypedArray(reqFeatures, parcelableFlags);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -195,5 +201,6 @@ public class PackageInfo implements Parcelable {
requestedPermissions = source.createStringArray();
signatures = source.createTypedArray(Signature.CREATOR);
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
+ reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fca005c..825eb85 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -159,8 +159,10 @@ public abstract class PackageManager {
/**
* {@link PackageInfo} flag: return information about
- * hardware preferences
- * {@link PackageInfo#configPreferences}
+ * hardware preferences in
+ * {@link PackageInfo#configPreferences PackageInfo.configPreferences} and
+ * requested features in {@link PackageInfo#reqFeatures
+ * PackageInfo.reqFeatures}.
*/
public static final int GET_CONFIGURATIONS = 0x00004000;
@@ -400,6 +402,14 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
/**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package uses a feature that is not available.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_MISSING_FEATURE = -17;
+
+ /**
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser was given a path that is not a file, or does not end with the expected
@@ -980,6 +990,16 @@ public abstract class PackageManager {
public abstract String[] getSystemSharedLibraryNames();
/**
+ * Get a list of features that are available on the
+ * system.
+ *
+ * @return An array of FeatureInfo classes describing the features
+ * that are available on the system, or null if there are none(!!).
+ *
+ */
+ public abstract FeatureInfo[] getSystemAvailableFeatures();
+
+ /**
* Determine the best action to perform for a given Intent. This is how
* {@link Intent#resolveActivity} finds an activity if a class has not
* been explicitly specified.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 96c9486..4399df4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -184,9 +184,12 @@ public class PackageParser {
int N = p.configPreferences.size();
if (N > 0) {
pi.configPreferences = new ConfigurationInfo[N];
- for (int i=0; i<N; i++) {
- pi.configPreferences[i] = p.configPreferences.get(i);
- }
+ p.configPreferences.toArray(pi.configPreferences);
+ }
+ N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
+ if (N > 0) {
+ pi.reqFeatures = new FeatureInfo[N];
+ p.reqFeatures.toArray(pi.reqFeatures);
}
}
if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
@@ -760,14 +763,32 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("uses-feature")) {
- ConfigurationInfo cPref = new ConfigurationInfo();
+ FeatureInfo fi = new FeatureInfo();
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestUsesFeature);
- cPref.reqGlEsVersion = sa.getInt(
- com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
- ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
+ fi.name = sa.getNonResourceString(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
+ if (fi.name == null) {
+ fi.reqGlEsVersion = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ }
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_required,
+ true)) {
+ fi.flags |= FeatureInfo.FLAG_REQUIRED;
+ }
sa.recycle();
- pkg.configPreferences.add(cPref);
+ if (pkg.reqFeatures == null) {
+ pkg.reqFeatures = new ArrayList<FeatureInfo>();
+ }
+ pkg.reqFeatures.add(fi);
+
+ if (fi.name == null) {
+ ConfigurationInfo cPref = new ConfigurationInfo();
+ cPref.reqGlEsVersion = fi.reqGlEsVersion;
+ pkg.configPreferences.add(cPref);
+ }
XmlUtils.skipCurrentTag(parser);
@@ -946,11 +967,6 @@ public class PackageParser {
}
}
- if (pkg.usesLibraries.size() > 0) {
- pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()];
- pkg.usesLibraries.toArray(pkg.usesLibraryFiles);
- }
-
if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
@@ -1436,11 +1452,28 @@ public class PackageParser {
String lname = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
+ boolean req = sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
+ true);
sa.recycle();
- if (lname != null && !owner.usesLibraries.contains(lname)) {
- owner.usesLibraries.add(lname.intern());
+ if (lname != null) {
+ if (req) {
+ if (owner.usesLibraries == null) {
+ owner.usesLibraries = new ArrayList<String>();
+ }
+ if (!owner.usesLibraries.contains(lname)) {
+ owner.usesLibraries.add(lname.intern());
+ }
+ } else {
+ if (owner.usesOptionalLibraries == null) {
+ owner.usesOptionalLibraries = new ArrayList<String>();
+ }
+ if (!owner.usesOptionalLibraries.contains(lname)) {
+ owner.usesOptionalLibraries.add(lname.intern());
+ }
+ }
}
XmlUtils.skipCurrentTag(parser);
@@ -2418,7 +2451,8 @@ public class PackageParser {
public ArrayList<String> protectedBroadcasts;
- public final ArrayList<String> usesLibraries = new ArrayList<String>();
+ public ArrayList<String> usesLibraries = null;
+ public ArrayList<String> usesOptionalLibraries = null;
public String[] usesLibraryFiles = null;
// We store the application meta-data independently to avoid multiple unwanted references
@@ -2466,6 +2500,11 @@ public class PackageParser {
public final ArrayList<ConfigurationInfo> configPreferences =
new ArrayList<ConfigurationInfo>();
+ /*
+ * Applications requested features
+ */
+ public ArrayList<FeatureInfo> reqFeatures = null;
+
public Package(String _name) {
packageName = _name;
applicationInfo.packageName = _name;
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d1079d0..ce421db 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -832,6 +832,14 @@
<declare-styleable name="AndroidManifestUsesLibrary" parent="AndroidManifestApplication">
<!-- Required name of the library you use. -->
<attr name="name" />
+ <!-- Specify whether this library is required for the application.
+ The default is true, meaning the application requires the
+ library, and does not want to be installed on devices that
+ don't support it. If you set this to false, then this will
+ allow the application to be installed even if the library
+ doesn't exist, and you will need to check for its presence
+ dynamically at runtime. -->
+ <attr name="required" />
</declare-styleable>
<!-- The <code>supports-screens</code> specifies the screen dimensions an
diff --git a/data/etc/android.hardware.camera.autofocus.xml b/data/etc/android.hardware.camera.autofocus.xml
new file mode 100644
index 0000000..d6e2b90
--- /dev/null
+++ b/data/etc/android.hardware.camera.autofocus.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard set of features for an auto-focus camera. -->
+<permissions>
+ <feature name="android.hardware.camera" />
+ <feature name="android.hardware.camera.autofocus" />
+</permissions>
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 2f4d716..8ec6ec3 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -35,6 +35,7 @@ import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
@@ -88,6 +89,7 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
@@ -221,6 +223,14 @@ class PackageManagerService extends IPackageManager.Stub {
// etc/permissions.xml file.
final HashMap<String, String> mSharedLibraries = new HashMap<String, String>();
+ // Temporary for building the final shared libraries for an .apk.
+ String[] mTmpSharedLibraries = null;
+
+ // These are the features this devices supports that were read from the
+ // etc/permissions.xml file.
+ final HashMap<String, FeatureInfo> mAvailableFeatures =
+ new HashMap<String, FeatureInfo>();
+
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
@@ -671,7 +681,21 @@ class PackageManagerService extends IPackageManager.Stub {
+ parser.getPositionDescription());
} else {
Log.i(TAG, "Got library " + lname + " in " + lfile);
- this.mSharedLibraries.put(lname, lfile);
+ mSharedLibraries.put(lname, lfile);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+
+ } else if ("feature".equals(name)) {
+ String fname = parser.getAttributeValue(null, "name");
+ if (fname == null) {
+ Log.w(TAG, "<feature> without name at "
+ + parser.getPositionDescription());
+ } else {
+ Log.i(TAG, "Got feature " + fname);
+ FeatureInfo fi = new FeatureInfo();
+ fi.name = fname;
+ mAvailableFeatures.put(fname, fi);
}
XmlUtils.skipCurrentTag(parser);
continue;
@@ -1001,12 +1025,30 @@ class PackageManagerService extends IPackageManager.Stub {
Set<String> libSet;
synchronized (mPackages) {
libSet = mSharedLibraries.keySet();
+ int size = libSet.size();
+ if (size > 0) {
+ String[] libs = new String[size];
+ libSet.toArray(libs);
+ return libs;
+ }
}
- int size = libSet.size();
- if (size > 0) {
- String[] libs = new String[size];
- libSet.toArray(libs);
- return libs;
+ return null;
+ }
+
+ public FeatureInfo[] getSystemAvailableFeatures() {
+ Collection<FeatureInfo> featSet;
+ synchronized (mPackages) {
+ featSet = mAvailableFeatures.values();
+ int size = featSet.size();
+ if (size > 0) {
+ FeatureInfo[] features = new FeatureInfo[size+1];
+ featSet.toArray(features);
+ FeatureInfo fi = new FeatureInfo();
+ fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ features[size] = fi;
+ return features;
+ }
}
return null;
}
@@ -2065,17 +2107,62 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
// Check all shared libraries and map to their actual file path.
- if (pkg.usesLibraryFiles != null) {
- for (int i=0; i<pkg.usesLibraryFiles.length; i++) {
- String file = mSharedLibraries.get(pkg.usesLibraryFiles[i]);
+ if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
+ if (mTmpSharedLibraries == null ||
+ mTmpSharedLibraries.length < mSharedLibraries.size()) {
+ mTmpSharedLibraries = new String[mSharedLibraries.size()];
+ }
+ int num = 0;
+ int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
+ for (int i=0; i<N; i++) {
+ String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
if (file == null) {
Log.e(TAG, "Package " + pkg.packageName
+ " requires unavailable shared library "
- + pkg.usesLibraryFiles[i] + "; ignoring!");
+ + pkg.usesLibraries.get(i) + "; failing!");
mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
return null;
}
- pkg.usesLibraryFiles[i] = file;
+ mTmpSharedLibraries[num] = file;
+ num++;
+ }
+ N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
+ for (int i=0; i<N; i++) {
+ String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
+ if (file == null) {
+ Log.w(TAG, "Package " + pkg.packageName
+ + " desires unavailable shared library "
+ + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
+ } else {
+ mTmpSharedLibraries[num] = file;
+ num++;
+ }
+ }
+ if (num > 0) {
+ pkg.usesLibraryFiles = new String[num];
+ System.arraycopy(mTmpSharedLibraries, 0,
+ pkg.usesLibraryFiles, 0, num);
+ }
+
+ if (pkg.reqFeatures != null) {
+ N = pkg.reqFeatures.size();
+ for (int i=0; i<N; i++) {
+ FeatureInfo fi = pkg.reqFeatures.get(i);
+ if ((fi.flags&FeatureInfo.FLAG_REQUIRED) == 0) {
+ // Don't care.
+ continue;
+ }
+
+ if (fi.name != null) {
+ if (mAvailableFeatures.get(fi.name) == null) {
+ Log.e(TAG, "Package " + pkg.packageName
+ + " requires unavailable feature "
+ + fi.name + "; failing!");
+ mLastScanError = PackageManager.INSTALL_FAILED_MISSING_FEATURE;
+ return null;
+ }
+ }
+ }
}
}
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index 4a50c5d..beb9044 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -22,6 +22,7 @@ import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstallObserver;
@@ -424,6 +425,11 @@ public class MockPackageManager extends PackageManager {
}
@Override
+ public FeatureInfo[] getSystemAvailableFeatures() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean isSafeMode() {
throw new UnsupportedOperationException();
}
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f4afd7f..790b474 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -730,8 +730,6 @@ int doDump(Bundle* bundle)
} else if (tag == "uses-permission") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
if (error == "") {
- int opt = getIntegerAttribute(tree,
- REQUIRED_ATTR, NULL, 1);
if (name == "android.permission.CAMERA") {
hasCameraPermission = true;
}
@@ -772,7 +770,10 @@ int doDump(Bundle* bundle)
fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string());
goto bail;
}
- printf("uses-library:'%s'\n", libraryName.string());
+ int req = getIntegerAttribute(tree,
+ REQUIRED_ATTR, NULL, 1);
+ printf("uses-library%s:'%s'\n",
+ req ? "" : "-not-required", libraryName.string());
} else if (tag == "receiver") {
withinReceiver = true;
receiverName = getAttribute(tree, NAME_ATTR, &error);