More device policy work: clarify password modes, monkeying.

Clarifies what the password modes mean, renaming them to "quality"
and updating their documentation and the implementation to follow.

Also adds a facility to find out if a monkey is running, which I
need for the api demo to avoid letting it wipe the device.
diff --git a/api/current.xml b/api/current.xml
index 3b6e031..85908c1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -17644,6 +17644,17 @@
 <exception name="SecurityException" type="java.lang.SecurityException">
 </exception>
 </method>
+<method name="isUserAMonkey"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="killBackgroundProcesses"
  return="void"
  abstract="false"
@@ -20457,7 +20468,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="mode" type="int">
+<parameter name="quality" type="int">
 </parameter>
 </method>
 <method name="getPasswordMinimumLength"
@@ -20473,7 +20484,7 @@
 <parameter name="admin" type="android.content.ComponentName">
 </parameter>
 </method>
-<method name="getPasswordMode"
+<method name="getPasswordQuality"
  return="int"
  abstract="false"
  native="false"
@@ -20592,7 +20603,7 @@
 <parameter name="length" type="int">
 </parameter>
 </method>
-<method name="setPasswordMode"
+<method name="setPasswordQuality"
  return="void"
  abstract="false"
  native="false"
@@ -20604,7 +20615,7 @@
 >
 <parameter name="admin" type="android.content.ComponentName">
 </parameter>
-<parameter name="mode" type="int">
+<parameter name="quality" type="int">
 </parameter>
 </method>
 <method name="wipeData"
@@ -20664,40 +20675,40 @@
  visibility="public"
 >
 </field>
-<field name="PASSWORD_MODE_ALPHANUMERIC"
+<field name="PASSWORD_QUALITY_ALPHANUMERIC"
  type="int"
  transient="false"
  volatile="false"
- value="3000"
+ value="196608"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 </field>
-<field name="PASSWORD_MODE_NUMERIC"
+<field name="PASSWORD_QUALITY_NUMERIC"
  type="int"
  transient="false"
  volatile="false"
- value="2000"
+ value="131072"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 </field>
-<field name="PASSWORD_MODE_SOMETHING"
+<field name="PASSWORD_QUALITY_SOMETHING"
  type="int"
  transient="false"
  volatile="false"
- value="1000"
+ value="65536"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 </field>
-<field name="PASSWORD_MODE_UNSPECIFIED"
+<field name="PASSWORD_QUALITY_UNSPECIFIED"
  type="int"
  transient="false"
  volatile="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 932ad53..e8ab51fd 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -957,4 +957,15 @@
         return null;
     }
     
+    /**
+     * Returns "true" if the user interface is currently being messed with
+     * by a monkey.
+     */
+    public static boolean isUserAMonkey() {
+        try {
+            return ActivityManagerNative.getDefault().isUserAMonkey();
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 09b88ee..2e39c10 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1178,6 +1178,14 @@
             int enterAnim = data.readInt();
             int exitAnim = data.readInt();
             overridePendingTransition(token, packageName, enterAnim, exitAnim);
+            reply.writeNoException();
+            return true;
+        }
+        
+        case IS_USER_A_MONKEY_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            reply.writeInt(isUserAMonkey() ? 1 : 0);
+            reply.writeNoException();
             return true;
         }
         }
@@ -2598,5 +2606,17 @@
         reply.recycle();
     }
     
+    public boolean isUserAMonkey() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(IS_USER_A_MONKEY_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean res = reply.readInt() != 0;
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+    
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
index 50b342b..ab9c44f 100644
--- a/core/java/android/app/DeviceAdminInfo.java
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -50,7 +50,7 @@
     
     /**
      * A type of policy that this device admin can use: limit the passwords
-     * that the user can select, via {@link DevicePolicyManager#setPasswordMode}
+     * 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"
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index 779db3a..074a62f 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -88,7 +88,7 @@
     
     /**
      * Activity action: have the user enter a new password.  This activity
-     * should be launched after using {@link #setPasswordMode(ComponentName, int)}
+     * 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
@@ -149,32 +149,33 @@
     }
     
     /**
-     * Constant for {@link #setPasswordMode}: the policy has no requirements
-     * for the password.  Note that mode constants are ordered so that higher
+     * 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_MODE_UNSPECIFIED = 0;
+    public static final int PASSWORD_QUALITY_UNSPECIFIED = 0;
     
     /**
-     * Constant for {@link #setPasswordMode}: the policy requires some kind
-     * of password, but doesn't care what it is.  Note that mode constants
+     * 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_MODE_SOMETHING = 1000;
+    public static final int PASSWORD_QUALITY_SOMETHING = 0x10000;
     
     /**
-     * Constant for {@link #setPasswordMode}: the user must have at least a
-     * numeric password.  Note that mode constants are ordered so that higher
-     * values are more restrictive.
+     * 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_MODE_NUMERIC = 2000;
+    public static final int PASSWORD_QUALITY_NUMERIC = 0x20000;
     
     /**
-     * Constant for {@link #setPasswordMode}: the user must have at least an
-     * alphanumeric password.  Note that mode constants are ordered so that higher
-     * values are more restrictive.
+     * 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_MODE_ALPHANUMERIC = 3000;
+    public static final int PASSWORD_QUALITY_ALPHANUMERIC = 0x30000;
     
     /**
      * Called by an application that is administering the device to set the
@@ -185,8 +186,8 @@
      * take place immediately.  To prompt the user for a new password, use
      * {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
      * 
-     * <p>Mode constants are ordered so that higher values are more restrictive;
-     * thus the highest requested mode constant (between the policy set here,
+     * <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.
      * 
@@ -195,14 +196,14 @@
      * 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},
-     * {@link #PASSWORD_MODE_NUMERIC}, or {@link #PASSWORD_MODE_ALPHANUMERIC}.
+     * @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 setPasswordMode(ComponentName admin, int mode) {
+    public void setPasswordQuality(ComponentName admin, int quality) {
         if (mService != null) {
             try {
-                mService.setPasswordMode(admin, mode);
+                mService.setPasswordQuality(admin, quality);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -210,20 +211,20 @@
     }
     
     /**
-     * Retrieve the current minimum password mode for all admins
+     * 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 getPasswordMode(ComponentName admin) {
+    public int getPasswordQuality(ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getPasswordMode(admin);
+                return mService.getPasswordQuality(admin);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
         }
-        return PASSWORD_MODE_UNSPECIFIED;
+        return PASSWORD_QUALITY_UNSPECIFIED;
     }
     
     /**
@@ -235,8 +236,8 @@
      * 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_MODE_NUMERIC} or {@link #PASSWORD_MODE_ALPHANUMERIC}
-     * with {@link #setPasswordMode}.
+     * {@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
@@ -275,18 +276,18 @@
     
     /**
      * Return the maximum password length that the device supports for a
-     * particular password mode.
+     * particular password quality.
      * @param mode The mode being interrogated.
      * @return Returns the maximum length that the user can enter.
      */
-    public int getPasswordMaximumLength(int mode) {
+    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 (mode, minimum length) that have been
+     * to meet the policy requirements (quality, minimum length) that have been
      * requested.
      * 
      * <p>The calling device admin must have requested
@@ -368,14 +369,15 @@
     }
     
     /**
-     * Force a new password on the user.  This takes effect immediately.  The
-     * given password must meet the current password minimum length constraint
-     * or it will be rejected.  The given password will be accepted regardless
-     * of the current password mode, automatically adjusting the password mode
-     * higher if needed to meet the requirements of all active administrators.
-     * (The string you give here is acceptable for any mode;
-     * if it contains only digits, that is still an acceptable alphanumeric
-     * password.)
+     * Force a new password 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
@@ -531,10 +533,10 @@
     /**
      * @hide
      */
-    public void setActivePasswordState(int mode, int length) {
+    public void setActivePasswordState(int quality, int length) {
         if (mService != null) {
             try {
-                mService.setActivePasswordState(mode, length);
+                mService.setActivePasswordState(quality, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 016d465..86f28bf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -288,6 +288,8 @@
     public void overridePendingTransition(IBinder token, String packageName,
             int enterAnim, int exitAnim) throws RemoteException;
     
+    public boolean isUserAMonkey() throws RemoteException;
+    
     /*
      * Private non-Binder interfaces
      */
@@ -450,4 +452,5 @@
     int OVERRIDE_PENDING_TRANSITION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+100;
     int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101;
     int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
+    int IS_USER_A_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+103;
 }
diff --git a/core/java/android/app/IDevicePolicyManager.aidl b/core/java/android/app/IDevicePolicyManager.aidl
index 8d804f9..ae5c4bf 100644
--- a/core/java/android/app/IDevicePolicyManager.aidl
+++ b/core/java/android/app/IDevicePolicyManager.aidl
@@ -25,8 +25,8 @@
  * {@hide}
  */
 interface IDevicePolicyManager {
-    void setPasswordMode(in ComponentName who, int mode);
-    int getPasswordMode(in ComponentName who);
+    void setPasswordQuality(in ComponentName who, int quality);
+    int getPasswordQuality(in ComponentName who);
     
     void setPasswordMinimumLength(in ComponentName who, int length);
     int getPasswordMinimumLength(in ComponentName who);
@@ -52,7 +52,7 @@
     void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
     void removeActiveAdmin(in ComponentName policyReceiver);
     
-    void setActivePasswordState(int mode, int length);
+    void setActivePasswordState(int quality, int length);
     void reportFailedPasswordAttempt();
     void reportSuccessfulPasswordAttempt();
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 6347146..f074b80 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -80,9 +80,10 @@
      * pin = digit-only password
      * password = alphanumeric password
      */
-    public static final int MODE_PATTERN = DevicePolicyManager.PASSWORD_MODE_SOMETHING;
-    public static final int MODE_PIN = DevicePolicyManager.PASSWORD_MODE_NUMERIC;
-    public static final int MODE_PASSWORD = DevicePolicyManager.PASSWORD_MODE_ALPHANUMERIC;
+    public static final int MODE_UNSPECIFIED = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+    public static final int MODE_PATTERN = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+    public static final int MODE_PIN = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+    public static final int MODE_PASSWORD = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
 
     /**
      * The minimum number of dots the user must include in a wrong pattern
@@ -132,13 +133,13 @@
      * @return
      */
     public int getRequestedPasswordMode() {
-        int policyMode = mDevicePolicyManager.getPasswordMode(null);
+        int policyMode = mDevicePolicyManager.getPasswordQuality(null);
         switch (policyMode) {
-            case DevicePolicyManager.PASSWORD_MODE_ALPHANUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
                 return MODE_PASSWORD;
-            case DevicePolicyManager.PASSWORD_MODE_NUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
                 return MODE_PIN;
-            case DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED:
+            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
                 return MODE_PATTERN;
         }
         return MODE_PATTERN;
@@ -158,16 +159,16 @@
     }
 
     public void setActivePasswordState(int mode, int length) {
-        int policyMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+        int policyMode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         switch (mode) {
             case MODE_PATTERN:
-                policyMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+                policyMode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
                 break;
             case MODE_PIN:
-                policyMode = DevicePolicyManager.PASSWORD_MODE_NUMERIC;
+                policyMode = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
                 break;
             case MODE_PASSWORD:
-                policyMode = DevicePolicyManager.PASSWORD_MODE_ALPHANUMERIC;
+                policyMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
                 break;
         }
         mDevicePolicyManager.setActivePasswordState(policyMode, length);
@@ -302,7 +303,7 @@
                 DevicePolicyManager dpm = (DevicePolicyManager)mContext.getSystemService(
                         Context.DEVICE_POLICY_SERVICE);
                 dpm.setActivePasswordState(
-                        DevicePolicyManager.PASSWORD_MODE_SOMETHING, pattern.size());
+                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern.size());
             }
         } catch (FileNotFoundException fnfe) {
             // Cant do much, unless we want to fail over to using the settings provider
@@ -314,7 +315,65 @@
     }
 
     /**
-     * Save a lock password.
+     * Compare the given password and mode, ensuring that the password meets
+     * the mode and returning the minimum mode needed for the given password.
+     * @param password The password to be used.
+     * @param reqMode The desired password mode.
+     * @return Returns {@link #MODE_UNSPECIFIED} if the password is not
+     * good enough for the given mode.  Otherwise, returns either the original
+     * reqMode or something better if that is needed for the given password.
+     */
+    static public int adjustPasswordMode(String password, int reqMode) {
+        boolean hasDigit = false;
+        boolean hasNonDigit = false;
+        final int len = password.length();
+        for (int i = 0; i < len; i++) {
+            if (Character.isDigit(password.charAt(i))) {
+                hasDigit = true;
+            } else {
+                hasNonDigit = true;
+            }
+        }
+        
+        // First check if it is sufficient.
+        switch (reqMode) {
+            case MODE_PASSWORD: {
+                if (!hasDigit || !hasNonDigit) {
+                    return MODE_UNSPECIFIED;
+                }
+            } break;
+            
+            case MODE_PIN:
+            case MODE_PATTERN: {
+                // Whatever we have is acceptable; we may need to promote the
+                // mode later.
+            } break;
+            
+            default:
+                // If it isn't a mode we specifically know, then fail fast.
+                Log.w(TAG, "adjustPasswordMode: unknown mode " + reqMode);
+                return MODE_UNSPECIFIED;
+        }
+        
+        // Do we need to promote?
+        if (hasNonDigit) {
+            if (reqMode < MODE_PASSWORD) {
+                reqMode = MODE_PASSWORD;
+            }
+        }
+        if (hasDigit) {
+            if (reqMode < MODE_PIN) {
+                reqMode = MODE_PIN;
+            }
+        }
+        
+        return reqMode;
+    }
+    
+    /**
+     * Save a lock password.  Does not ensure that the pattern is as good
+     * as the requested mode, but will adjust the mode to be as good as the
+     * pattern.
      * @param password The password to save
      */
     public void saveLockPassword(String password, int mode) {
@@ -331,9 +390,9 @@
             }
             raf.close();
             if (password != null) {
-                int textMode = TextUtils.isDigitsOnly(password) ? MODE_PIN : MODE_PASSWORD;
-                if (textMode > mode) {
-                    mode = textMode;
+                int finalMode = adjustPasswordMode(password, mode);
+                if (mode < finalMode) {
+                    mode = finalMode;
                 }
                 setLong(PASSWORD_TYPE_KEY, mode);
                 DevicePolicyManager dpm = (DevicePolicyManager)mContext.getSystemService(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 979955c..015b487 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -71,7 +71,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 47;
+    private static final int DATABASE_VERSION = 48;
 
     private Context mContext;
 
@@ -595,8 +595,23 @@
            upgradeVersion = 47;
        }
 
+        
+        if (upgradeVersion == 47) {
+            /*
+             * The password mode constants have changed again; reset back to no
+             * password.
+             */
+            db.beginTransaction();
+            try {
+                db.execSQL("DELETE FROM system WHERE name='lockscreen.password_type';");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+           upgradeVersion = 48;
+       }
 
-        if (upgradeVersion != currentVersion) {
+       if (upgradeVersion != currentVersion) {
             Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
                     + ", must wipe the settings provider");
             db.execSQL("DROP TABLE IF EXISTS system");
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 17a3ab8..e4ee4ae 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -64,7 +64,7 @@
 
     IPowerManager mIPowerManager;
     
-    int mActivePasswordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+    int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     int mActivePasswordLength = 0;
     int mFailedPasswordAttempts = 0;
     
@@ -76,7 +76,7 @@
     static class ActiveAdmin {
         final DeviceAdminInfo info;
         
-        int passwordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+        int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         int minimumPasswordLength = 0;
         long maximumTimeToUnlock = 0;
         int maximumFailedPasswordsForWipe = 0;
@@ -89,17 +89,17 @@
         
         void writeToXml(XmlSerializer out)
                 throws IllegalArgumentException, IllegalStateException, IOException {
-            if (passwordMode != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
-                out.startTag(null, "password-mode");
-                out.attribute(null, "value", Integer.toString(passwordMode));
-                out.endTag(null, "password-mode");
+            if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                out.startTag(null, "password-quality");
+                out.attribute(null, "value", Integer.toString(passwordQuality));
+                out.endTag(null, "password-quality");
                 if (minimumPasswordLength > 0) {
                     out.startTag(null, "min-password-length");
                     out.attribute(null, "value", Integer.toString(minimumPasswordLength));
                     out.endTag(null, "mn-password-length");
                 }
             }
-            if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
+            if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                 out.startTag(null, "max-time-to-unlock");
                 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
                 out.endTag(null, "max-time-to-unlock");
@@ -121,8 +121,8 @@
                     continue;
                 }
                 String tag = parser.getName();
-                if ("password-mode".equals(tag)) {
-                    passwordMode = Integer.parseInt(
+                if ("password-quality".equals(tag)) {
+                    passwordQuality = Integer.parseInt(
                             parser.getAttributeValue(null, "value"));
                 } else if ("min-password-length".equals(tag)) {
                     minimumPasswordLength = Integer.parseInt(
@@ -435,34 +435,34 @@
         }
     }
     
-    public void setPasswordMode(ComponentName who, int mode) {
+    public void setPasswordQuality(ComponentName who, int mode) {
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
-            if (ap.passwordMode != mode) {
-                ap.passwordMode = mode;
+            if (ap.passwordQuality != mode) {
+                ap.passwordQuality = mode;
                 saveSettingsLocked();
             }
         }
     }
     
-    public int getPasswordMode(ComponentName who) {
+    public int getPasswordQuality(ComponentName who) {
         synchronized (this) {
-            int mode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+            int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
             
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
-                return admin != null ? admin.passwordMode : mode;
+                return admin != null ? admin.passwordQuality : mode;
             }
             
             final int N = mAdminList.size();
             for  (int i=0; i<N; i++) {
                 ActiveAdmin admin = mAdminList.get(i);
-                if (mode < admin.passwordMode) {
-                    mode = admin.passwordMode;
+                if (mode < admin.passwordQuality) {
+                    mode = admin.passwordQuality;
                 }
             }
             return mode;
@@ -509,7 +509,7 @@
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
-            return mActivePasswordMode >= getPasswordMode(null)
+            return mActivePasswordQuality >= getPasswordQuality(null)
                     && mActivePasswordLength >= getPasswordMinimumLength(null);
         }
     }
@@ -563,14 +563,24 @@
     }
     
     public boolean resetPassword(String password) {
-        int mode;
+        int quality;
         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,
                     DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
-            mode = getPasswordMode(null);
-            if (password.length() < getPasswordMinimumLength(null)) {
+            quality = getPasswordQuality(null);
+            if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                int adjQuality = LockPatternUtils.adjustPasswordMode(password, quality);
+                if (adjQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                    Log.w(TAG, "resetPassword: password does not meet quality " + quality);
+                    return false;
+                }
+                quality = adjQuality;
+            }
+            int length = getPasswordMinimumLength(null);
+            if (password.length() < length) {
+                Log.w(TAG, "resetPassword: password does not meet length " + length);
                 return false;
             }
         }
@@ -580,7 +590,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             LockPatternUtils utils = new LockPatternUtils(mContext);
-            utils.saveLockPassword(password, mode);
+            utils.saveLockPassword(password, quality);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -709,16 +719,16 @@
         }
     }
     
-    public void setActivePasswordState(int mode, int length) {
+    public void setActivePasswordState(int quality, int length) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
         
         synchronized (this) {
-            if (mActivePasswordMode != mode || mActivePasswordLength != length
+            if (mActivePasswordQuality != quality || mActivePasswordLength != length
                     || mFailedPasswordAttempts != 0) {
                 long ident = Binder.clearCallingIdentity();
                 try {
-                    mActivePasswordMode = mode;
+                    mActivePasswordQuality = quality;
                     mActivePasswordLength = length;
                     if (mFailedPasswordAttempts != 0) {
                         mFailedPasswordAttempts = 0;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c2c6e76..b723dcd 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8081,6 +8081,14 @@
         }
     }
 
+    public boolean isUserAMonkey() {
+        // For now the fact that there is a controller implies
+        // we have a monkey.
+        synchronized (this) {
+            return mController != null;
+        }
+    }
+    
     public void registerActivityWatcher(IActivityWatcher watcher) {
         mWatchers.register(watcher);
     }