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:
Dianne Hackborn
2009-08-27 20:08:01 -07:00
parent 5511c66955
commit 49237345d8
14 changed files with 527 additions and 40 deletions

View File

@ -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"

View File

@ -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 {

View File

@ -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() {

View 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;

View 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 &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);
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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

View 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>

View File

@ -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;
}
}
}
}
}

View File

@ -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();

View File

@ -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);