summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-01-22 11:31:30 -0800
committerDianne Hackborn <hackbod@google.com>2010-01-26 12:28:15 -0800
commit8aa2e8939c61d788cbc192098465e79f584e173a (patch)
tree83f2ea06758e1bb3f28a8fabedae29c3a5b89582
parent148fea03caed2a082387c45ae12a91561b8e41e5 (diff)
downloadframeworks_base-8aa2e8939c61d788cbc192098465e79f584e173a.zip
frameworks_base-8aa2e8939c61d788cbc192098465e79f584e173a.tar.gz
frameworks_base-8aa2e8939c61d788cbc192098465e79f584e173a.tar.bz2
More device admin work: description, policy control.
There is now a description attribute associated with all components, that can supply user-visible information about what the component does. We use this to show such information about device admins, and wallpapers are also updated to be able to show this in addition to the existing description in their meta-data. This also defines security control for admins, requiring that they declare the policies they will touch, and enforcing that they do so to be able to use various APIs.
-rw-r--r--api/current.xml117
-rw-r--r--core/java/android/app/DeviceAdmin.java12
-rw-r--r--core/java/android/app/DeviceAdminInfo.java199
-rw-r--r--core/java/android/app/DevicePolicyManager.java32
-rw-r--r--core/java/android/app/WallpaperInfo.java35
-rw-r--r--core/java/android/content/pm/ComponentInfo.java29
-rw-r--r--core/java/android/content/pm/PackageParser.java17
-rwxr-xr-xcore/java/android/widget/AppSecurityPermissions.java26
-rw-r--r--core/res/res/values/attrs_manifest.xml5
-rw-r--r--core/res/res/values/strings.xml34
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java51
11 files changed, 523 insertions, 34 deletions
diff --git a/api/current.xml b/api/current.xml
index 8cd368f..cd200c1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -20148,6 +20148,34 @@
visibility="public"
>
</method>
+<method name="getTagForPolicy"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policyIdent" type="int">
+</parameter>
+</method>
+<method name="loadDescription"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pm" type="android.content.pm.PackageManager">
+</parameter>
+<exception name="Resources.NotFoundException" type="android.content.res.Resources.NotFoundException">
+</exception>
+</method>
<method name="loadIcon"
return="android.graphics.drawable.Drawable"
abstract="false"
@@ -20174,6 +20202,19 @@
<parameter name="pm" type="android.content.pm.PackageManager">
</parameter>
</method>
+<method name="usesPolicy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policyIdent" type="int">
+</parameter>
+</method>
<method name="writeToParcel"
return="void"
abstract="false"
@@ -20199,6 +20240,72 @@
visibility="public"
>
</field>
+<field name="USES_POLICY_FORCE_LOCK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_LIMIT_PASSWORD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_LIMIT_UNLOCK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_RESET_PASSWORD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_WATCH_LOGIN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_WIPE_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="DevicePolicyManager"
extends="java.lang.Object"
@@ -41567,6 +41674,16 @@
visibility="public"
>
</field>
+<field name="descriptionRes"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="enabled"
type="boolean"
transient="false"
diff --git a/core/java/android/app/DeviceAdmin.java b/core/java/android/app/DeviceAdmin.java
index 16832db..9750d6e 100644
--- a/core/java/android/app/DeviceAdmin.java
+++ b/core/java/android/app/DeviceAdmin.java
@@ -82,6 +82,10 @@ public class DeviceAdmin extends BroadcastReceiver {
* {@link DevicePolicyManager#getMinimumPasswordLength()
* DevicePolicyManager.getMinimumPasswordLength()}. You will generally
* handle this in {@link DeviceAdmin#onPasswordChanged(Context, Intent)}.
+ *
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to receive
+ * this broadcast.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PASSWORD_CHANGED
@@ -94,6 +98,10 @@ public class DeviceAdmin extends BroadcastReceiver {
* {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
* DevicePolicyManager.getCurrentFailedPasswordAttempts()}. You will generally
* handle this in {@link DeviceAdmin#onPasswordFailed(Context, Intent)}.
+ *
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
+ * this broadcast.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PASSWORD_FAILED
@@ -102,6 +110,10 @@ public class DeviceAdmin extends BroadcastReceiver {
/**
* Action sent to a device administrator when the user has successfully
* entered their password, after failing one or more times.
+ *
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
+ * this broadcast.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PASSWORD_SUCCEEDED
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
index eac6e46..92fdbc8 100644
--- a/core/java/android/app/DeviceAdminInfo.java
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -19,21 +19,28 @@ package android.app;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.R;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.content.res.Resources.NotFoundException;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Printer;
+import android.util.SparseArray;
import android.util.Xml;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
/**
* This class is used to specify meta information of a device administrator
@@ -43,11 +50,123 @@ public final class DeviceAdminInfo implements Parcelable {
static final String TAG = "DeviceAdminInfo";
/**
+ * A type of policy that this device admin can use: limit the passwords
+ * that the user can select, via {@link DevicePolicyManager#setPasswordMode}
+ * and {@link DevicePolicyManager#setMinimumPasswordLength}.
+ *
+ * <p>To control this policy, the device admin must have a "limit-password"
+ * tag in the "uses-policies" section of its meta-data.
+ */
+ public static final int USES_POLICY_LIMIT_PASSWORD = 0;
+
+ /**
+ * A type of policy that this device admin can use: able to watch login
+ * attempts from the user, via {@link DeviceAdmin#ACTION_PASSWORD_FAILED},
+ * {@link DeviceAdmin#ACTION_PASSWORD_SUCCEEDED}, and
+ * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts}.
+ *
+ * <p>To control this policy, the device admin must have a "watch-login"
+ * tag in the "uses-policies" section of its meta-data.
+ */
+ public static final int USES_POLICY_WATCH_LOGIN = 1;
+
+ /**
+ * A type of policy that this device admin can use: able to reset the
+ * user's password via
+ * {@link DevicePolicyManager#resetPassword}.
+ *
+ * <p>To control this policy, the device admin must have a "reset-password"
+ * tag in the "uses-policies" section of its meta-data.
+ */
+ public static final int USES_POLICY_RESET_PASSWORD = 2;
+
+ /**
+ * A type of policy that this device admin can use: able to limit the
+ * maximum lock timeout for the device via
+ * {@link DevicePolicyManager#setMaximumTimeToLock}.
+ *
+ * <p>To control this policy, the device admin must have a "limit-unlock"
+ * tag in the "uses-policies" section of its meta-data.
+ */
+ public static final int USES_POLICY_LIMIT_UNLOCK = 3;
+
+ /**
+ * A type of policy that this device admin can use: able to force the device
+ * to lock via{@link DevicePolicyManager#lockNow}.
+ *
+ * <p>To control this policy, the device admin must have a "force-lock"
+ * tag in the "uses-policies" section of its meta-data.
+ */
+ public static final int USES_POLICY_FORCE_LOCK = 4;
+
+ /**
+ * A type of policy that this device admin can use: able to factory
+ * reset the device, erasing all of the user's data, via
+ * {@link DevicePolicyManager#wipeData}.
+ *
+ * <p>To control this policy, the device admin must have a "wipe-data"
+ * tag in the "uses-policies" section of its meta-data.
+ */
+ public static final int USES_POLICY_WIPE_DATA = 5;
+
+ /** @hide */
+ public static class PolicyInfo {
+ final public String tag;
+ final public int label;
+ final public int description;
+
+ public PolicyInfo(String tagIn, int labelIn, int descriptionIn) {
+ tag = tagIn;
+ label = labelIn;
+ description = descriptionIn;
+ }
+ }
+
+ static HashMap<String, Integer> sKnownPolicies = new HashMap<String, Integer>();
+ static SparseArray<PolicyInfo> sRevKnownPolicies = new SparseArray<PolicyInfo>();
+
+ static {
+ sRevKnownPolicies.put(USES_POLICY_LIMIT_PASSWORD,
+ new PolicyInfo("limit-password",
+ com.android.internal.R.string.policylab_limitPassword,
+ com.android.internal.R.string.policydesc_limitPassword));
+ sRevKnownPolicies.put(USES_POLICY_WATCH_LOGIN,
+ new PolicyInfo("watch-login",
+ com.android.internal.R.string.policylab_watchLogin,
+ com.android.internal.R.string.policydesc_watchLogin));
+ sRevKnownPolicies.put(USES_POLICY_RESET_PASSWORD,
+ new PolicyInfo("reset-password",
+ com.android.internal.R.string.policylab_resetPassword,
+ com.android.internal.R.string.policydesc_resetPassword));
+ sRevKnownPolicies.put(USES_POLICY_LIMIT_UNLOCK,
+ new PolicyInfo("limit-unlock",
+ com.android.internal.R.string.policylab_limitUnlock,
+ com.android.internal.R.string.policydesc_limitUnlock));
+ sRevKnownPolicies.put(USES_POLICY_FORCE_LOCK,
+ new PolicyInfo("force-lock",
+ com.android.internal.R.string.policylab_forceLock,
+ com.android.internal.R.string.policydesc_forceLock));
+ sRevKnownPolicies.put(USES_POLICY_WIPE_DATA,
+ new PolicyInfo("wipe-data",
+ com.android.internal.R.string.policylab_wipeData,
+ com.android.internal.R.string.policydesc_wipeData));
+ for (int i=0; i<sRevKnownPolicies.size(); i++) {
+ sKnownPolicies.put(sRevKnownPolicies.valueAt(i).tag,
+ sRevKnownPolicies.keyAt(i));
+ }
+ }
+
+ /**
* The BroadcastReceiver that implements this device admin component.
*/
final ResolveInfo mReceiver;
/**
+ * The policies this administrator needs access to.
+ */
+ int mUsesPolicies;
+
+ /**
* Constructor.
*
* @param context The Context in which we are parsing the device admin.
@@ -86,6 +205,32 @@ public final class DeviceAdminInfo implements Parcelable {
com.android.internal.R.styleable.Wallpaper);
sa.recycle();
+
+ int outerDepth = parser.getDepth();
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals("uses-policies")) {
+ int innerDepth = parser.getDepth();
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String policyName = parser.getName();
+ Integer val = sKnownPolicies.get(policyName);
+ if (val != null) {
+ mUsesPolicies |= 1 << val.intValue();
+ } else {
+ Log.w(TAG, "Unknown tag under uses-policies of "
+ + getComponent() + ": " + policyName);
+ }
+ }
+ }
+ }
} finally {
if (parser != null) parser.close();
}
@@ -93,6 +238,7 @@ public final class DeviceAdminInfo implements Parcelable {
DeviceAdminInfo(Parcel source) {
mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
+ mUsesPolicies = source.readInt();
}
/**
@@ -137,6 +283,26 @@ public final class DeviceAdminInfo implements Parcelable {
}
/**
+ * Load user-visible description associated with this device admin.
+ *
+ * @param pm Supply a PackageManager used to load the device admin's
+ * resources.
+ */
+ public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
+ if (mReceiver.activityInfo.descriptionRes != 0) {
+ String packageName = mReceiver.resolvePackageName;
+ ApplicationInfo applicationInfo = null;
+ if (packageName == null) {
+ packageName = mReceiver.activityInfo.packageName;
+ applicationInfo = mReceiver.activityInfo.applicationInfo;
+ }
+ return pm.getText(packageName,
+ mReceiver.activityInfo.descriptionRes, applicationInfo);
+ }
+ throw new NotFoundException();
+ }
+
+ /**
* Load the user-displayed icon for this device admin.
*
* @param pm Supply a PackageManager used to load the device admin's
@@ -146,6 +312,38 @@ public final class DeviceAdminInfo implements Parcelable {
return mReceiver.loadIcon(pm);
}
+ /**
+ * Return true if the device admin has requested that it be able to use
+ * the given policy control. The possible policy identifier inputs are:
+ * {@link #USES_POLICY_LIMIT_PASSWORD}, {@link #USES_POLICY_WATCH_LOGIN},
+ * {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_LIMIT_UNLOCK},
+ * {@link #USES_POLICY_FORCE_LOCK}, {@link #USES_POLICY_WIPE_DATA}.
+ */
+ public boolean usesPolicy(int policyIdent) {
+ return (mUsesPolicies & (1<<policyIdent)) != 0;
+ }
+
+ /**
+ * Return the XML tag name for the given policy identifier. Valid identifiers
+ * are as per {@link #usesPolicy(int)}. If the given identifier is not
+ * known, null is returned.
+ */
+ public String getTagForPolicy(int policyIdent) {
+ return sRevKnownPolicies.get(policyIdent).tag;
+ }
+
+ /** @hide */
+ public ArrayList<PolicyInfo> getUsedPolicies() {
+ ArrayList<PolicyInfo> res = new ArrayList<PolicyInfo>();
+ for (int i=0; i<sRevKnownPolicies.size(); i++) {
+ int ident = sRevKnownPolicies.keyAt(i);
+ if (usesPolicy(ident)) {
+ res.add(sRevKnownPolicies.valueAt(i));
+ }
+ }
+ return res;
+ }
+
public void dump(Printer pw, String prefix) {
pw.println(prefix + "Receiver:");
mReceiver.dump(pw, prefix + " ");
@@ -164,6 +362,7 @@ public final class DeviceAdminInfo implements Parcelable {
*/
public void writeToParcel(Parcel dest, int flags) {
mReceiver.writeToParcel(dest, flags);
+ dest.writeInt(mUsesPolicies);
}
/**
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index 538ba5b..25e3230 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -163,6 +163,10 @@ public class DevicePolicyManager {
* the user's preference, and any other considerations) is the one that
* is in effect.
*
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
* @param admin Which {@link DeviceAdmin} this request is associated with.
* @param mode The new desired mode. One of
* {@link #PASSWORD_MODE_UNSPECIFIED}, {@link #PASSWORD_MODE_SOMETHING},
@@ -205,6 +209,10 @@ public class DevicePolicyManager {
* {@link #PASSWORD_MODE_NUMERIC} or {@link #PASSWORD_MODE_ALPHANUMERIC}
* with {@link #setPasswordMode}.
*
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
* @param admin Which {@link DeviceAdmin} this request is associated with.
* @param length The new desired minimum password length. A value of 0
* means there is no restriction.
@@ -239,6 +247,10 @@ public class DevicePolicyManager {
* to meet the policy requirements (mode, minimum length) that have been
* requested.
*
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
* @return Returns true if the password meets the current requirements,
* else false.
*/
@@ -256,6 +268,10 @@ public class DevicePolicyManager {
/**
* Retrieve the number of times the user has failed at entering a
* password since that last successful password entry.
+ *
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call
+ * this method; if it has not, a security exception will be thrown.
*/
public int getCurrentFailedPasswordAttempts() {
if (mService != null) {
@@ -277,6 +293,10 @@ public class DevicePolicyManager {
* if it contains only digits, that is still an acceptable alphanumeric
* password.)
*
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
* @param password The new password for the user.
* @return Returns true if the password was applied, or false if it is
* not acceptable for the current constraints.
@@ -297,6 +317,10 @@ public class DevicePolicyManager {
* maximum time for user activity until the device will lock. This limits
* the length that the user can set. It takes effect immediately.
*
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_UNLOCK} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
* @param admin Which {@link DeviceAdmin} this request is associated with.
* @param timeMs The new desired maximum time to lock in milliseconds.
* A value of 0 means there is no restriction.
@@ -329,6 +353,10 @@ public class DevicePolicyManager {
/**
* Make the device lock immediately, as if the lock screen timeout has
* expired at the point of this call.
+ *
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
+ * this method; if it has not, a security exception will be thrown.
*/
public void lockNow() {
if (mService != null) {
@@ -345,6 +373,10 @@ public class DevicePolicyManager {
* erasing all user data while next booting up. External storage such
* as SD cards will not be erased.
*
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
* @param flags Bit mask of additional options: currently must be 0.
*/
public void wipeData(int flags) {
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 1612ac9..5ca3fb5 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -21,6 +21,7 @@ import org.xmlpull.v1.XmlPullParserException;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -204,7 +205,7 @@ public final class WallpaperInfo implements Parcelable {
return pm.getDrawable(mService.serviceInfo.packageName,
mThumbnailResource,
- null);
+ mService.serviceInfo.applicationInfo);
}
/**
@@ -212,25 +213,33 @@ public final class WallpaperInfo implements Parcelable {
*/
public CharSequence loadAuthor(PackageManager pm) throws NotFoundException {
if (mAuthorResource <= 0) throw new NotFoundException();
- return pm.getText(
- (mService.resolvePackageName != null)
- ? mService.resolvePackageName
- : getPackageName(),
- mAuthorResource,
- null);
+ String packageName = mService.resolvePackageName;
+ ApplicationInfo applicationInfo = null;
+ if (packageName == null) {
+ packageName = mService.serviceInfo.packageName;
+ applicationInfo = mService.serviceInfo.applicationInfo;
+ }
+ return pm.getText(packageName, mAuthorResource, applicationInfo);
}
/**
* Return a brief summary of this wallpaper's behavior.
*/
public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
+ String packageName = mService.resolvePackageName;
+ ApplicationInfo applicationInfo = null;
+ if (packageName == null) {
+ packageName = mService.serviceInfo.packageName;
+ applicationInfo = mService.serviceInfo.applicationInfo;
+ }
+ if (mService.serviceInfo.descriptionRes != 0) {
+ return pm.getText(packageName, mService.serviceInfo.descriptionRes,
+ applicationInfo);
+
+ }
if (mDescriptionResource <= 0) throw new NotFoundException();
- return pm.getText(
- (mService.resolvePackageName != null)
- ? mService.resolvePackageName
- : getPackageName(),
- mDescriptionResource,
- null);
+ return pm.getText(packageName, mDescriptionResource,
+ mService.serviceInfo.applicationInfo);
}
/**
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 73c9244..338c62b6 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2008 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;
import android.graphics.drawable.Drawable;
@@ -27,6 +43,13 @@ public class ComponentInfo extends PackageItemInfo {
public String processName;
/**
+ * A string resource identifier (in the package's resources) containing
+ * a user-readable description of the component. From the "description"
+ * attribute or, if not set, 0.
+ */
+ public int descriptionRes;
+
+ /**
* Indicates whether or not this component may be instantiated. Note that this value can be
* overriden by the one in its parent {@link ApplicationInfo}.
*/
@@ -47,6 +70,7 @@ public class ComponentInfo extends PackageItemInfo {
super(orig);
applicationInfo = orig.applicationInfo;
processName = orig.processName;
+ descriptionRes = orig.descriptionRes;
enabled = orig.enabled;
exported = orig.exported;
}
@@ -108,6 +132,9 @@ public class ComponentInfo extends PackageItemInfo {
super.dumpFront(pw, prefix);
pw.println(prefix + "enabled=" + enabled + " exported=" + exported
+ " processName=" + processName);
+ if (descriptionRes != 0) {
+ pw.println(prefix + "description=" + descriptionRes);
+ }
}
protected void dumpBack(Printer pw, String prefix) {
@@ -124,6 +151,7 @@ public class ComponentInfo extends PackageItemInfo {
super.writeToParcel(dest, parcelableFlags);
applicationInfo.writeToParcel(dest, parcelableFlags);
dest.writeString(processName);
+ dest.writeInt(descriptionRes);
dest.writeInt(enabled ? 1 : 0);
dest.writeInt(exported ? 1 : 0);
}
@@ -132,6 +160,7 @@ public class ComponentInfo extends PackageItemInfo {
super(source);
applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
processName = source.readString();
+ descriptionRes = source.readInt();
enabled = (source.readInt() != 0);
exported = (source.readInt() != 0);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8a5df32..bbde0a6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -119,15 +119,18 @@ public class PackageParser {
static class ParseComponentArgs extends ParsePackageItemArgs {
final String[] sepProcesses;
final int processRes;
+ final int descriptionRes;
final int enabledRes;
int flags;
ParseComponentArgs(Package _owner, String[] _outError,
int _nameRes, int _labelRes, int _iconRes,
- String[] _sepProcesses, int _processRes,int _enabledRes) {
+ String[] _sepProcesses, int _processRes,
+ int _descriptionRes, int _enabledRes) {
super(_owner, _outError, _nameRes, _labelRes, _iconRes);
sepProcesses = _sepProcesses;
processRes = _processRes;
+ descriptionRes = _descriptionRes;
enabledRes = _enabledRes;
}
}
@@ -1602,6 +1605,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestActivity_icon,
mSeparateProcesses,
com.android.internal.R.styleable.AndroidManifestActivity_process,
+ com.android.internal.R.styleable.AndroidManifestActivity_description,
com.android.internal.R.styleable.AndroidManifestActivity_enabled);
}
@@ -1803,6 +1807,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
mSeparateProcesses,
0,
+ com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
mParseActivityAliasArgs.tag = "<activity-alias>";
}
@@ -1837,6 +1842,9 @@ public class PackageParser {
info.nonLocalizedLabel = target.info.nonLocalizedLabel;
info.launchMode = target.info.launchMode;
info.processName = target.info.processName;
+ if (info.descriptionRes == 0) {
+ info.descriptionRes = target.info.descriptionRes;
+ }
info.screenOrientation = target.info.screenOrientation;
info.taskAffinity = target.info.taskAffinity;
info.theme = target.info.theme;
@@ -1926,6 +1934,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestProvider_icon,
mSeparateProcesses,
com.android.internal.R.styleable.AndroidManifestProvider_process,
+ com.android.internal.R.styleable.AndroidManifestProvider_description,
com.android.internal.R.styleable.AndroidManifestProvider_enabled);
mParseProviderArgs.tag = "<provider>";
}
@@ -2188,6 +2197,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestService_icon,
mSeparateProcesses,
com.android.internal.R.styleable.AndroidManifestService_process,
+ com.android.internal.R.styleable.AndroidManifestService_description,
com.android.internal.R.styleable.AndroidManifestService_enabled);
mParseServiceArgs.tag = "<service>";
}
@@ -2640,6 +2650,11 @@ public class PackageParser {
owner.applicationInfo.processName, args.sa.getNonResourceString(args.processRes),
args.flags, args.sepProcesses, args.outError);
}
+
+ if (args.descriptionRes != 0) {
+ outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
+ }
+
outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
}
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index a09f23c..aa14c81 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -146,6 +146,19 @@ public class AppSecurityPermissions implements View.OnClickListener {
}
}
+ /**
+ * Utility to retrieve a view displaying a single permission.
+ */
+ public static View getPermissionItemView(Context context,
+ CharSequence grpName, CharSequence description, boolean dangerous) {
+ LayoutInflater inflater = (LayoutInflater)context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ Drawable icon = context.getResources().getDrawable(dangerous
+ ? R.drawable.ic_bullet_key_permission : R.drawable.ic_text_dot);
+ return getPermissionItemView(context, inflater, grpName,
+ description, dangerous, icon);
+ }
+
private void getAllUsedPermissions(int sharedUid, Set<PermissionInfo> permSet) {
String sharedPkgList[] = mPm.getPackagesForUid(sharedUid);
if(sharedPkgList == null || (sharedPkgList.length == 0)) {
@@ -304,15 +317,20 @@ public class AppSecurityPermissions implements View.OnClickListener {
mNoPermsView.setVisibility(View.VISIBLE);
}
- private View getPermissionItemView(CharSequence grpName, String permList,
+ private View getPermissionItemView(CharSequence grpName, CharSequence permList,
boolean dangerous) {
- View permView = mInflater.inflate(R.layout.app_permission_item, null);
- Drawable icon = dangerous ? mDangerousIcon : mNormalIcon;
+ return getPermissionItemView(mContext, mInflater, grpName, permList,
+ dangerous, dangerous ? mDangerousIcon : mNormalIcon);
+ }
+
+ private static View getPermissionItemView(Context context, LayoutInflater inflater,
+ CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) {
+ View permView = inflater.inflate(R.layout.app_permission_item, null);
TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
if (dangerous) {
- final Resources resources = mContext.getResources();
+ final Resources resources = context.getResources();
permGrpView.setTextColor(resources.getColor(R.color.perms_dangerous_grp_color));
permDescView.setTextColor(resources.getColor(R.color.perms_dangerous_perm_color));
}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c6ef3a0..7728c50 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -938,6 +938,7 @@
is a period then it is appended to your package name. -->
<attr name="name" />
<attr name="label" />
+ <attr name="description" />
<attr name="icon" />
<attr name="process" />
<attr name="authorities" />
@@ -1016,6 +1017,7 @@
is a period then it is appended to your package name. -->
<attr name="name" />
<attr name="label" />
+ <attr name="description" />
<attr name="icon" />
<attr name="permission" />
<attr name="process" />
@@ -1047,6 +1049,7 @@
is a period then it is appended to your package name. -->
<attr name="name" />
<attr name="label" />
+ <attr name="description" />
<attr name="icon" />
<attr name="permission" />
<attr name="process" />
@@ -1078,6 +1081,7 @@
<attr name="name" />
<attr name="theme" />
<attr name="label" />
+ <attr name="description" />
<attr name="icon" />
<attr name="launchMode" />
<attr name="screenOrientation" />
@@ -1130,6 +1134,7 @@
"com.mycompany.MyName". -->
<attr name="targetActivity" format="string" />
<attr name="label" />
+ <attr name="description" />
<attr name="icon" />
<attr name="permission" />
<!-- Specify whether the activity-alias is enabled or not (that is, can be instantiated by the system).
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 265dacd..0ef07ff 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1157,6 +1157,40 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_cache_filesystem">Allows an application to read and write the cache filesystem.</string>
+ <!-- Policy administration -->
+
+ <!-- Title of policy access to limiting the user's password choices -->
+ <string name="policylab_limitPassword">Limit password</string>
+ <!-- Description of policy access to limiting the user's password choices -->
+ <string name="policydesc_limitPassword">Restrict the types of passwords you
+ are allowed to use.</string>
+ <!-- Title of policy access to watch user login attempts -->
+ <string name="policylab_watchLogin">Watch login attempts</string>
+ <!-- Description of policy access to watch user login attempts -->
+ <string name="policydesc_watchLogin">Monitor attempts to login to
+ the device, in particular to respond to failed login attempts.</string>
+ <!-- Title of policy access to reset user's password -->
+ <string name="policylab_resetPassword">Reset your password</string>
+ <!-- Description of policy access to reset user's password -->
+ <string name="policydesc_resetPassword">Force your password
+ to a new value, requiring the administrator give it to you
+ before you can log in.</string>
+ <!-- Title of policy access to limiting the user's unlock timeout -->
+ <string name="policylab_limitUnlock">Limit lock timeout</string>
+ <!-- Description of policy access to limiting the user's unlock timeout -->
+ <string name="policydesc_limitUnlock">Restrict the unlock timeout
+ durations you can select.</string>
+ <!-- Title of policy access to force lock the device -->
+ <string name="policylab_forceLock">Force lock</string>
+ <!-- Description of policy access to limiting the user's password choices -->
+ <string name="policydesc_forceLock">Force the device to immediately lock,
+ requiring that its password is re-entered.</string>
+ <!-- Title of policy access to wipe the user's data -->
+ <string name="policylab_wipeData">Erase all data</string>
+ <!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_wipeData">Perform a factory reset, deleting
+ all of your data without any confirmation from you.</string>
+
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
<string-array name="phoneTypes">
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 36da4eb..fbd5317 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -91,7 +91,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return mIPowerManager;
}
- ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException {
+ ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
+ throws SecurityException {
if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingUid()) {
if (who != null) {
if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName)
@@ -99,20 +100,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new SecurityException("Current admin is not " + who);
}
}
+ if (!mActiveAdmin.info.usesPolicy(reqPolicy)) {
+ throw new SecurityException("Admin " + mActiveAdmin.info.getComponent()
+ + " did not specify uses-policy for: "
+ + mActiveAdmin.info.getTagForPolicy(reqPolicy));
+ }
return mActiveAdmin;
}
throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid());
}
-
- void sendAdminCommandLocked(ActiveAdmin policy, String action) {
+ void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Intent intent = new Intent(action);
- intent.setComponent(policy.info.getComponent());
+ intent.setComponent(admin.info.getComponent());
mContext.sendBroadcast(intent);
}
- void sendAdminCommandLocked(String action) {
+ void sendAdminCommandLocked(String action, int reqPolicy) {
if (mActiveAdmin != null) {
+ if (mActiveAdmin.info.usesPolicy(reqPolicy)) {
+ return;
+ }
sendAdminCommandLocked(mActiveAdmin, action);
}
}
@@ -353,7 +361,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
- ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.passwordMode != mode) {
ap.passwordMode = mode;
saveSettingsLocked();
@@ -373,7 +382,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
- ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordLength != length) {
ap.minimumPasswordLength = length;
saveSettingsLocked();
@@ -391,7 +401,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(null);
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
return mActivePasswordMode >= getPasswordMode()
&& mActivePasswordLength >= getMinimumPasswordLength();
}
@@ -401,7 +412,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(null);
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
return mFailedPasswordAttempts;
}
}
@@ -411,7 +423,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(null);
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
mode = getPasswordMode();
if (password.length() < getMinimumPasswordLength()) {
return false;
@@ -436,7 +449,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
- ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_UNLOCK);
if (ap.maximumTimeToUnlock != timeMs) {
ap.maximumTimeToUnlock = timeMs;
@@ -468,7 +482,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(null);
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
// STOPSHIP need to implement.
}
}
@@ -477,7 +492,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(null);
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_WIPE_DATA);
}
long ident = Binder.clearCallingIdentity();
try {
@@ -501,7 +517,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mActivePasswordMode = mode;
mActivePasswordLength = length;
mFailedPasswordAttempts = 0;
- sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED);
+ sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -517,7 +534,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
mFailedPasswordAttempts++;
- sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED);
+ sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -533,7 +551,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
mFailedPasswordAttempts = 0;
- sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED);
+ sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
} finally {
Binder.restoreCallingIdentity(ident);
}