Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8aa2e893 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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.
parent 148fea03
Loading
Loading
Loading
Loading
+117 −0
Original line number Diff line number Diff line
@@ -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"
+12 −0
Original line number Diff line number Diff line
@@ -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
+199 −0
Original line number Diff line number Diff line
@@ -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
@@ -42,11 +49,123 @@ import java.io.IOException;
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.
     * 
@@ -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();
    }
    
    /**
@@ -136,6 +282,26 @@ public final class DeviceAdminInfo implements Parcelable {
        return mReceiver.loadLabel(pm);
    }
    
    /**
     * 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.
     * 
@@ -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);
    }

    /**
+32 −0
Original line number Diff line number Diff line
@@ -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) {
+22 −13
Original line number Diff line number Diff line
@@ -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);
    }
    
    /**
Loading