Add platform infrastructure for features.
This introduces a new mechanism to define features associated with a platform, query the current device for the available features, and enforce that apps requiring features that aren't available can't be installed. Also now allows uses-library to specify that a library is optional, so the lack of such a library will not prevent the app from being installed (but if it does exist it will be correctly linked into the app). Change-Id: I5b369b46cfa0b3d37c9e08fd14ef1098a978e67b
This commit is contained in:
161
api/current.xml
161
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"
|
||||
|
@ -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;
|
||||
@ -1622,6 +1623,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 {
|
||||
|
@ -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 <uses-configuration> and the <uses-feature>tags.
|
||||
* AndroidManifest.xml's <uses-configuration> and <uses-feature> 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() {
|
||||
|
19
core/java/android/content/pm/FeatureInfo.aidl
Executable file
19
core/java/android/content/pm/FeatureInfo.aidl
Executable file
@ -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;
|
101
core/java/android/content/pm/FeatureInfo.java
Normal file
101
core/java/android/content/pm/FeatureInfo.java
Normal file
@ -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 <uses-feature> 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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
@ -399,6 +401,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)}
|
||||
@ -979,6 +989,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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
21
data/etc/android.hardware.camera.autofocus.xml
Normal file
21
data/etc/android.hardware.camera.autofocus.xml
Normal file
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
@ -423,6 +424,11 @@ public class MockPackageManager extends PackageManager {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureInfo[] getSystemAvailableFeatures() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafeMode() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user