Move DeviceAdmin APIs to android.app.admin.

Also add ability for admins to hide themselves when not in use,
a facility for admins to not allow other admins to reset
their password, and debug dumping.
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
new file mode 100644
index 0000000..c4de812
--- /dev/null
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2010 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.app.admin;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+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
+ * component.
+ */
+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#setPasswordQuality}
+     * and {@link DevicePolicyManager#setPasswordMinimumLength}.
+     * 
+     * <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 DeviceAdminReceiver#ACTION_PASSWORD_FAILED},
+     * {@link DeviceAdminReceiver#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 force the device
+     * to lock via{@link DevicePolicyManager#lockNow} or limit the
+     * maximum lock timeout for the device via
+     * {@link DevicePolicyManager#setMaximumTimeToLock}.
+     * 
+     * <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 = 3;
+
+    /**
+     * 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 = 4;
+
+    /** @hide */
+    public static class PolicyInfo {
+        public final int ident;
+        final public String tag;
+        final public int label;
+        final public int description;
+        
+        public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
+            ident = identIn;
+            tag = tagIn;
+            label = labelIn;
+            description = descriptionIn;
+        }
+    }
+    
+    static ArrayList<PolicyInfo> sPoliciesDisplayOrder = new ArrayList<PolicyInfo>();
+    static HashMap<String, Integer> sKnownPolicies = new HashMap<String, Integer>();
+    static SparseArray<PolicyInfo> sRevKnownPolicies = new SparseArray<PolicyInfo>();
+    
+    static {
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
+                com.android.internal.R.string.policylab_wipeData,
+                com.android.internal.R.string.policydesc_wipeData));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
+                com.android.internal.R.string.policylab_resetPassword,
+                com.android.internal.R.string.policydesc_resetPassword));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_LIMIT_PASSWORD, "limit-password",
+                com.android.internal.R.string.policylab_limitPassword,
+                com.android.internal.R.string.policydesc_limitPassword));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
+                com.android.internal.R.string.policylab_watchLogin,
+                com.android.internal.R.string.policydesc_watchLogin));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
+                com.android.internal.R.string.policylab_forceLock,
+                com.android.internal.R.string.policydesc_forceLock));
+        
+        for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
+            PolicyInfo pi = sPoliciesDisplayOrder.get(i);
+            sRevKnownPolicies.put(pi.ident, pi);
+            sKnownPolicies.put(pi.tag, pi.ident);
+        }
+    }
+    
+    /**
+     * The BroadcastReceiver that implements this device admin component.
+     */
+    final ResolveInfo mReceiver;
+    
+    /**
+     * Whether this should be visible to the user.
+     */
+    boolean mVisible;
+    
+    /**
+     * The policies this administrator needs access to.
+     */
+    int mUsesPolicies;
+    
+    /**
+     * Constructor.
+     * 
+     * @param context The Context in which we are parsing the device admin.
+     * @param receiver The ResolveInfo returned from the package manager about
+     * this device admin's component.
+     */
+    public DeviceAdminInfo(Context context, ResolveInfo receiver)
+            throws XmlPullParserException, IOException {
+        mReceiver = receiver;
+        ActivityInfo ai = receiver.activityInfo;
+        
+        PackageManager pm = context.getPackageManager();
+        
+        XmlResourceParser parser = null;
+        try {
+            parser = ai.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
+            if (parser == null) {
+                throw new XmlPullParserException("No "
+                        + DeviceAdminReceiver.DEVICE_ADMIN_META_DATA + " meta-data");
+            }
+        
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+            
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+            }
+            
+            String nodeName = parser.getName();
+            if (!"device-admin".equals(nodeName)) {
+                throw new XmlPullParserException(
+                        "Meta-data does not start with device-admin tag");
+            }
+            
+            TypedArray sa = context.getResources().obtainAttributes(attrs,
+                    com.android.internal.R.styleable.DeviceAdmin);
+
+            mVisible = sa.getBoolean(
+                    com.android.internal.R.styleable.DeviceAdmin_visible, true);
+            
+            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();
+        }
+    }
+
+    DeviceAdminInfo(Parcel source) {
+        mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
+        mUsesPolicies = source.readInt();
+    }
+    
+    /**
+     * Return the .apk package that implements this device admin.
+     */
+    public String getPackageName() {
+        return mReceiver.activityInfo.packageName;
+    }
+    
+    /**
+     * Return the class name of the receiver component that implements
+     * this device admin.
+     */
+    public String getReceiverName() {
+        return mReceiver.activityInfo.name;
+    }
+
+    /**
+     * Return the raw information about the receiver implementing this
+     * device admin.  Do not modify the returned object.
+     */
+    public ActivityInfo getActivityInfo() {
+        return mReceiver.activityInfo;
+    }
+
+    /**
+     * Return the component of the receiver that implements this device admin.
+     */
+    public ComponentName getComponent() {
+        return new ComponentName(mReceiver.activityInfo.packageName,
+                mReceiver.activityInfo.name);
+    }
+    
+    /**
+     * Load the user-displayed label for this device admin.
+     * 
+     * @param pm Supply a PackageManager used to load the device admin's
+     * resources.
+     */
+    public CharSequence loadLabel(PackageManager pm) {
+        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.
+     * 
+     * @param pm Supply a PackageManager used to load the device admin's
+     * resources.
+     */
+    public Drawable loadIcon(PackageManager pm) {
+        return mReceiver.loadIcon(pm);
+    }
+    
+    /**
+     * Returns whether this device admin would like to be visible to the
+     * user, even when it is not enabled.
+     */
+    public boolean isVisible() {
+        return mVisible;
+    }
+    
+    /**
+     * 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_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<sPoliciesDisplayOrder.size(); i++) {
+            PolicyInfo pi = sPoliciesDisplayOrder.get(i);
+            if (usesPolicy(pi.ident)) {
+                res.add(pi);
+            }
+        }
+        return res;
+    }
+    
+    /** @hide */
+    public void writePoliciesToXml(XmlSerializer out)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        out.attribute(null, "flags", Integer.toString(mUsesPolicies));
+    }
+    
+    /** @hide */
+    public void readPoliciesFromXml(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        mUsesPolicies = Integer.parseInt(
+                parser.getAttributeValue(null, "flags"));
+    }
+    
+    public void dump(Printer pw, String prefix) {
+        pw.println(prefix + "Receiver:");
+        mReceiver.dump(pw, prefix + "  ");
+    }
+    
+    @Override
+    public String toString() {
+        return "DeviceAdminInfo{" + mReceiver.activityInfo.name + "}";
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        mReceiver.writeToParcel(dest, flags);
+        dest.writeInt(mUsesPolicies);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<DeviceAdminInfo> CREATOR =
+            new Parcelable.Creator<DeviceAdminInfo>() {
+        public DeviceAdminInfo createFromParcel(Parcel source) {
+            return new DeviceAdminInfo(source);
+        }
+
+        public DeviceAdminInfo[] newArray(int size) {
+            return new DeviceAdminInfo[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
new file mode 100644
index 0000000..b4dd9e7
--- /dev/null
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2010 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.app.admin;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Base class for implementing a device administration component.  This
+ * class provides a convenience for interpreting the raw intent actions
+ * that are sent by the system.
+ * 
+ * <p>The callback methods, like the base
+ * {@link BroadcastReceiver#onReceive(Context, Intent) BroadcastReceiver.onReceive()}
+ * method, happen on the main thread of the process.  Thus long running
+ * operations must be done on another thread.  Note that because a receiver
+ * is done once returning from its receive function, such long-running operations
+ * should probably be done in a {@link Service}.
+ * 
+ * <p>When publishing your DeviceAdmin subclass as a receiver, it must
+ * handle {@link #ACTION_DEVICE_ADMIN_ENABLED} and require the
+ * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission.  A typical
+ * manifest entry would look like:</p>
+ * 
+ * {@sample development/samples/ApiDemos/AndroidManifest.xml device_admin_declaration}
+ *   
+ * <p>The meta-data referenced here provides addition information specific
+ * to the device administrator, as parsed by the {@link DeviceAdminInfo} class.
+ * A typical file would be:</p>
+ * 
+ * {@sample development/samples/ApiDemos/res/xml/device_admin_sample.xml meta_data}
+ */
+public class DeviceAdminReceiver extends BroadcastReceiver {
+    private static String TAG = "DevicePolicy";
+    private static boolean DEBUG = false;
+    private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
+
+    /**
+     * This is the primary action that a device administrator must implement to be
+     * allowed to manage a device.  This will be set to the receiver
+     * when the user enables it for administration.  You will generally
+     * handle this in {@link DeviceAdminReceiver#onEnabled(Context, Intent)}.  To be
+     * supported, the receiver must also require the
+     * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission so
+     * that other applications can not abuse it.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEVICE_ADMIN_ENABLED
+            = "android.app.action.DEVICE_ADMIN_ENABLED";
+
+    /**
+     * Action sent to a device administrator when the user has requested to
+     * disable it, but before this has actually been done.  This gives you
+     * a chance to supply a message to the user about the impact of
+     * disabling your admin, by setting the extra field
+     * {@link #EXTRA_DISABLE_WARNING} in the result Intent.  If not set,
+     * no warning will be displayed.  If set, the given text will be shown
+     * to the user before they disable your admin.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
+            = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
+    
+    /**
+     * A CharSequence that can be shown to the user informing them of the
+     * impact of disabling your admin.
+     *
+     * @see #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
+     */
+    public static final String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
+    
+    /**
+     * Action sent to a device administrator when the user has disabled
+     * it.  Upon return, the application no longer has access to the
+     * protected device policy manager APIs.  You will generally
+     * handle this in {@link DeviceAdminReceiver#onDisabled(Context, Intent)}.  Note
+     * that this action will be
+     * sent the receiver regardless of whether it is explicitly listed in
+     * its intent filter.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEVICE_ADMIN_DISABLED
+            = "android.app.action.DEVICE_ADMIN_DISABLED";
+    
+    /**
+     * Action sent to a device administrator when the user has changed the
+     * password of their device.  You can at this point check the characteristics
+     * of the new password with {@link DevicePolicyManager#isActivePasswordSufficient()
+     * DevicePolicyManager.isActivePasswordSufficient()}.
+     * You will generally
+     * handle this in {@link DeviceAdminReceiver#onPasswordChanged}.
+     * 
+     * <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
+            = "android.app.action.ACTION_PASSWORD_CHANGED";
+    
+    /**
+     * Action sent to a device administrator when the user has failed at
+     * attempted to enter the password.  You can at this point check the
+     * number of failed password attempts there have been with
+     * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts
+     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}.  You will generally
+     * handle this in {@link DeviceAdminReceiver#onPasswordFailed}.
+     * 
+     * <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
+            = "android.app.action.ACTION_PASSWORD_FAILED";
+    
+    /**
+     * 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
+            = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
+    
+    /**
+     * Name under which an DevicePolicy component publishes information
+     * about itself.  This meta-data must reference an XML resource containing
+     * a device-admin tag.  XXX TO DO: describe syntax.
+     */
+    public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
+    
+    private DevicePolicyManager mManager;
+    private ComponentName mWho;
+    
+    /**
+     * Retrieve the DevicePolicyManager interface for this administrator to work
+     * with the system.
+     */
+    public DevicePolicyManager getManager(Context context) {
+        if (mManager != null) {
+            return mManager;
+        }
+        mManager = (DevicePolicyManager)context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        return mManager;
+    }
+    
+    /**
+     * Retrieve the ComponentName describing who this device administrator is, for
+     * use in {@link DevicePolicyManager} APIs that require the administrator to
+     * identify itself.
+     */
+    public ComponentName getWho(Context context) {
+        if (mWho != null) {
+            return mWho;
+        }
+        mWho = new ComponentName(context, getClass());
+        return mWho;
+    }
+    
+    /**
+     * Called after the administrator is first enabled, as a result of
+     * receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}.  At this point you
+     * can use {@link DevicePolicyManager} to set your desired policies.
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onEnabled(Context context, Intent intent) {
+    }
+    
+    /**
+     * Called when the user has asked to disable the administrator, as a result of
+     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED}, giving you
+     * a chance to present a warning message to them.  The message is returned
+     * as the result; if null is returned (the default implementation), no
+     * message will be displayed.
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     * @return Return the warning message to display to the user before
+     * being disabled; if null is returned, no message is displayed.
+     */
+    public CharSequence onDisableRequested(Context context, Intent intent) {
+        return null;
+    }
+    
+    /**
+     * Called prior to the administrator being disabled, as a result of
+     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLED}.  Upon return, you
+     * can no longer use the protected parts of the {@link DevicePolicyManager}
+     * API.
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onDisabled(Context context, Intent intent) {
+    }
+    
+    /**
+     * Called after the user has changed their password, as a result of
+     * receiving {@link #ACTION_PASSWORD_CHANGED}.  At this point you
+     * can use {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
+     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}
+     * to retrieve the active password characteristics.
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onPasswordChanged(Context context, Intent intent) {
+    }
+    
+    /**
+     * Called after the user has failed at entering their current password, as a result of
+     * receiving {@link #ACTION_PASSWORD_FAILED}.  At this point you
+     * can use {@link DevicePolicyManager} to retrieve the number of failed
+     * password attempts.
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onPasswordFailed(Context context, Intent intent) {
+    }
+    
+    /**
+     * Called after the user has succeeded at entering their current password,
+     * as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}.  This will
+     * only be received the first time they succeed after having previously
+     * failed.
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onPasswordSucceeded(Context context, Intent intent) {
+    }
+    
+    /**
+     * Intercept standard device administrator broadcasts.  Implementations
+     * should not override this method; it is better to implement the
+     * convenience callbacks for each action.
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (ACTION_PASSWORD_CHANGED.equals(action)) {
+            onPasswordChanged(context, intent);
+        } else if (ACTION_PASSWORD_FAILED.equals(action)) {
+            onPasswordFailed(context, intent);
+        } else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
+            onPasswordSucceeded(context, intent);
+        } else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
+            onEnabled(context, intent);
+        } else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
+            CharSequence res = onDisableRequested(context, intent);
+            if (res != null) {
+                Bundle extras = getResultExtras(true);
+                extras.putCharSequence(EXTRA_DISABLE_WARNING, res);
+            }
+        } else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
+            onDisabled(context, intent);
+        }
+    }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
new file mode 100644
index 0000000..2d9b415
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2010 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.app.admin;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.admin.IDevicePolicyManager.Stub;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Handler;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Public interface for managing policies enforced on a device.  Most clients
+ * of this class must have published a {@link DeviceAdminReceiver} that the user
+ * has currently enabled.
+ */
+public class DevicePolicyManager {
+    private static String TAG = "DevicePolicyManager";
+    private static boolean DEBUG = false;
+    private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
+
+    private final Context mContext;
+    private final IDevicePolicyManager mService;
+    
+    private final Handler mHandler;
+
+    private DevicePolicyManager(Context context, Handler handler) {
+        mContext = context;
+        mHandler = handler;
+        mService = IDevicePolicyManager.Stub.asInterface(
+                ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+    }
+
+    /** @hide */
+    public static DevicePolicyManager create(Context context, Handler handler) {
+        DevicePolicyManager me = new DevicePolicyManager(context, handler);
+        return me.mService != null ? me : null;
+    }
+    
+    /**
+     * Activity action: ask the user to add a new device administrator to the system.
+     * The desired policy is the ComponentName of the policy in the
+     * {@link #EXTRA_DEVICE_ADMIN} extra field.  This will invoke a UI to
+     * bring the user through adding the device administrator to the system (or
+     * allowing them to reject it).
+     * 
+     * <p>You can optionally include the {@link #EXTRA_ADD_EXPLANATION}
+     * field to provide the user with additional explanation (in addition
+     * to your component's description) about what is being added.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ADD_DEVICE_ADMIN
+            = "android.app.action.ADD_DEVICE_ADMIN";
+    
+    /**
+     * The ComponentName of the administrator component.
+     *
+     * @see #ACTION_ADD_DEVICE_ADMIN
+     */
+    public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
+    
+    /**
+     * An optional CharSequence providing additional explanation for why the
+     * admin is being added.
+     *
+     * @see #ACTION_ADD_DEVICE_ADMIN
+     */
+    public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
+    
+    /**
+     * Activity action: have the user enter a new password.  This activity
+     * should be launched after using {@link #setPasswordQuality(ComponentName, int)}
+     * or {@link #setPasswordMinimumLength(ComponentName, int)} to have the
+     * user enter a new password that meets the current requirements.  You can
+     * use {@link #isActivePasswordSufficient()} to determine whether you need
+     * to have the user select a new password in order to meet the current
+     * constraints.  Upon being resumed from this activity,
+     * you can check the new password characteristics to see if they are
+     * sufficient.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SET_NEW_PASSWORD
+            = "android.app.action.SET_NEW_PASSWORD";
+    
+    /**
+     * Return true if the given administrator component is currently
+     * active (enabled) in the system.
+     */
+    public boolean isAdminActive(ComponentName who) {
+        if (mService != null) {
+            try {
+                return mService.isAdminActive(who);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Return a list of all currently active device administrator's component
+     * names.  Note that if there are no administrators than null may be
+     * returned.
+     */
+    public List<ComponentName> getActiveAdmins() {
+        if (mService != null) {
+            try {
+                return mService.getActiveAdmins();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * @hide
+     */
+    public boolean packageHasActiveAdmins(String packageName) {
+        if (mService != null) {
+            try {
+                return mService.packageHasActiveAdmins(packageName);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Remove a current administration component.  This can only be called
+     * by the application that owns the administration component; if you
+     * try to remove someone else's component, a security exception will be
+     * thrown.
+     */
+    public void removeActiveAdmin(ComponentName who) {
+        if (mService != null) {
+            try {
+                mService.removeActiveAdmin(who);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Constant for {@link #setPasswordQuality}: the policy has no requirements
+     * for the password.  Note that quality constants are ordered so that higher
+     * values are more restrictive.
+     */
+    public static final int PASSWORD_QUALITY_UNSPECIFIED = 0;
+    
+    /**
+     * Constant for {@link #setPasswordQuality}: the policy requires some kind
+     * of password, but doesn't care what it is.  Note that quality constants
+     * are ordered so that higher values are more restrictive.
+     */
+    public static final int PASSWORD_QUALITY_SOMETHING = 0x10000;
+    
+    /**
+     * Constant for {@link #setPasswordQuality}: the user must have entered a
+     * password containing at least numeric characters.  Note that quality
+     * constants are ordered so that higher values are more restrictive.
+     */
+    public static final int PASSWORD_QUALITY_NUMERIC = 0x20000;
+    
+    /**
+     * Constant for {@link #setPasswordQuality}: the user must have entered a
+     * password containing at least <em>both></em> numeric <em>and</em>
+     * alphabeter (or other symbol) characters.  Note that quality constants are
+     * ordered so that higher values are more restrictive.
+     */
+    public static final int PASSWORD_QUALITY_ALPHANUMERIC = 0x30000;
+    
+    /**
+     * Called by an application that is administering the device to set the
+     * password restrictions it is imposing.  After setting this, the user
+     * will not be able to enter a new password that is not at least as
+     * restrictive as what has been set.  Note that the current password
+     * will remain until the user has set a new one, so the change does not
+     * take place immediately.  To prompt the user for a new password, use
+     * {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
+     * 
+     * <p>Quality constants are ordered so that higher values are more restrictive;
+     * thus the highest requested quality constant (between the policy set here,
+     * 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 DeviceAdminReceiver} this request is associated with.
+     * @param quality The new desired quality.  One of
+     * {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING},
+     * {@link #PASSWORD_QUALITY_NUMERIC}, or {@link #PASSWORD_QUALITY_ALPHANUMERIC}.
+     */
+    public void setPasswordQuality(ComponentName admin, int quality) {
+        if (mService != null) {
+            try {
+                mService.setPasswordQuality(admin, quality);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Retrieve the current minimum password quality for all admins
+     * or a particular one.
+     * @param admin The name of the admin component to check, or null to aggregate
+     * all admins.
+     */
+    public int getPasswordQuality(ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getPasswordQuality(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return PASSWORD_QUALITY_UNSPECIFIED;
+    }
+    
+    /**
+     * Called by an application that is administering the device to set the
+     * minimum allowed password length.  After setting this, the user
+     * will not be able to enter a new password that is not at least as
+     * restrictive as what has been set.  Note that the current password
+     * will remain until the user has set a new one, so the change does not
+     * take place immediately.  To prompt the user for a new password, use
+     * {@link #ACTION_SET_NEW_PASSWORD} after setting this value.  This
+     * constraint is only imposed if the administrator has also requested either
+     * {@link #PASSWORD_QUALITY_NUMERIC} or {@link #PASSWORD_QUALITY_ALPHANUMERIC}
+     * with {@link #setPasswordQuality}.
+     * 
+     * <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 DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired minimum password length.  A value of 0
+     * means there is no restriction.
+     */
+    public void setPasswordMinimumLength(ComponentName admin, int length) {
+        if (mService != null) {
+            try {
+                mService.setPasswordMinimumLength(admin, length);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Retrieve the current minimum password length for all admins
+     * or a particular one.
+     * @param admin The name of the admin component to check, or null to aggregate
+     * all admins.
+     */
+    public int getPasswordMinimumLength(ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getPasswordMinimumLength(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+    
+    /**
+     * Return the maximum password length that the device supports for a
+     * particular password quality.
+     * @param quality The quality being interrogated.
+     * @return Returns the maximum length that the user can enter.
+     */
+    public int getPasswordMaximumLength(int quality) {
+        // Kind-of arbitrary.
+        return 16;
+    }
+    
+    /**
+     * Determine whether the current password the user has set is sufficient
+     * to meet the policy requirements (quality, 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.
+     */
+    public boolean isActivePasswordSufficient() {
+        if (mService != null) {
+            try {
+                return mService.isActivePasswordSufficient();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * 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) {
+            try {
+                return mService.getCurrentFailedPasswordAttempts();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Setting this to a value greater than zero enables a built-in policy
+     * that will perform a device wipe after too many incorrect
+     * device-unlock passwords have been entered.  This built-in policy combines
+     * watching for failed passwords and wiping the device, and requires
+     * that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
+     * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}}.
+     * 
+     * <p>To implement any other policy (e.g. wiping data for a particular
+     * application only, erasing or revoking credentials, or reporting the
+     * failure to a server), you should implement
+     * {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)}
+     * instead.  Do not use this API, because if the maximum count is reached,
+     * the device will be wiped immediately, and your callback will not be invoked.
+     * 
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param num The number of failed password attempts at which point the
+     * device will wipe its data.
+     */
+    public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) {
+        if (mService != null) {
+            try {
+                mService.setMaximumFailedPasswordsForWipe(admin, num);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Retrieve the current maximum number of login attempts that are allowed
+     * before the device wipes itself, for all admins
+     * or a particular one.
+     * @param admin The name of the admin component to check, or null to aggregate
+     * all admins.
+     */
+    public int getMaximumFailedPasswordsForWipe(ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getMaximumFailedPasswordsForWipe(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+    
+    /**
+     * Flag for {@link #resetPassword}: don't allow other admins to change
+     * the password again until the user has entered it.
+     */
+    public static final int RESET_PASSWORD_REQUIRE_ENTRY = 0x0001;
+    
+    /**
+     * Force a new device unlock password (the password needed to access the
+     * entire device, not for individual accounts) on the user.  This takes
+     * effect immediately.
+     * The given password must be sufficient for the
+     * current password quality and length constraints as returned by
+     * {@link #getPasswordQuality(ComponentName)} and
+     * {@link #getPasswordMinimumLength(ComponentName)}; if it does not meet
+     * these constraints, then it will be rejected and false returned.  Note
+     * that the password may be a stronger quality (containing alphanumeric
+     * characters when the requested quality is only numeric), in which case
+     * the currently active quality will be increased to match.
+     * 
+     * <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.
+     * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}.
+     * @return Returns true if the password was applied, or false if it is
+     * not acceptable for the current constraints.
+     */
+    public boolean resetPassword(String password, int flags) {
+        if (mService != null) {
+            try {
+                return mService.resetPassword(password, flags);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Called by an application that is administering the device to set the
+     * 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_FORCE_LOCK} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     * 
+     * @param admin Which {@link DeviceAdminReceiver} 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.
+     */
+    public void setMaximumTimeToLock(ComponentName admin, long timeMs) {
+        if (mService != null) {
+            try {
+                mService.setMaximumTimeToLock(admin, timeMs);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Retrieve the current maximum time to unlock for all admins
+     * or a particular one.
+     * @param admin The name of the admin component to check, or null to aggregate
+     * all admins.
+     */
+    public long getMaximumTimeToLock(ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getMaximumTimeToLock(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+    
+    /**
+     * 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) {
+            try {
+                mService.lockNow();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Ask the user date be wiped.  This will cause the device to reboot,
+     * 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) {
+        if (mService != null) {
+            try {
+                mService.wipeData(flags);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * @hide
+     */
+    public void setActiveAdmin(ComponentName policyReceiver) {
+        if (mService != null) {
+            try {
+                mService.setActiveAdmin(policyReceiver);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * @hide
+     */
+    public DeviceAdminInfo getAdminInfo(ComponentName cn) {
+        ActivityInfo ai;
+        try {
+            ai = mContext.getPackageManager().getReceiverInfo(cn,
+                    PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+            return null;
+        }
+        
+        ResolveInfo ri = new ResolveInfo();
+        ri.activityInfo = ai;
+        
+        try {
+            return new DeviceAdminInfo(mContext, ri);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Unable to parse device policy " + cn, e);
+            return null;
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to parse device policy " + cn, e);
+            return null;
+        }
+    }
+    
+    /**
+     * @hide
+     */
+    public void getRemoveWarning(ComponentName admin, RemoteCallback result) {
+        if (mService != null) {
+            try {
+                mService.getRemoveWarning(admin, result);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void setActivePasswordState(int quality, int length) {
+        if (mService != null) {
+            try {
+                mService.setActivePasswordState(quality, length);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * @hide
+     */
+    public void reportFailedPasswordAttempt() {
+        if (mService != null) {
+            try {
+                mService.reportFailedPasswordAttempt();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * @hide
+     */
+    public void reportSuccessfulPasswordAttempt() {
+        if (mService != null) {
+            try {
+                mService.reportSuccessfulPasswordAttempt();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
new file mode 100644
index 0000000..6fc4dc5
--- /dev/null
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -0,0 +1,59 @@
+/*
+**
+** Copyright 2010, 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.app.admin;
+
+import android.content.ComponentName;
+import android.os.RemoteCallback;
+
+/**
+ * Internal IPC interface to the device policy service.
+ * {@hide}
+ */
+interface IDevicePolicyManager {
+    void setPasswordQuality(in ComponentName who, int quality);
+    int getPasswordQuality(in ComponentName who);
+    
+    void setPasswordMinimumLength(in ComponentName who, int length);
+    int getPasswordMinimumLength(in ComponentName who);
+    
+    boolean isActivePasswordSufficient();
+    int getCurrentFailedPasswordAttempts();
+    
+    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
+    int getMaximumFailedPasswordsForWipe(in ComponentName admin);
+    
+    boolean resetPassword(String password, int flags);
+    
+    void setMaximumTimeToLock(in ComponentName who, long timeMs);
+    long getMaximumTimeToLock(in ComponentName who);
+    
+    void lockNow();
+    
+    void wipeData(int flags);
+    
+    void setActiveAdmin(in ComponentName policyReceiver);
+    boolean isAdminActive(in ComponentName policyReceiver);
+    List<ComponentName> getActiveAdmins();
+    boolean packageHasActiveAdmins(String packageName);
+    void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
+    void removeActiveAdmin(in ComponentName policyReceiver);
+    
+    void setActivePasswordState(int quality, int length);
+    void reportFailedPasswordAttempt();
+    void reportSuccessfulPasswordAttempt();
+}