More device policy manager / admin work.

Update API with some new features, re-arrange how you check for valid
passwords, and start hooking up the back-end implementation.
diff --git a/api/current.xml b/api/current.xml
index 01ff582..689f5dd 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -20208,28 +20208,6 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<method name="getActiveMinimumPasswordLength"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getActivePasswordMode"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getCurrentFailedPasswordAttempts"
  return="int"
  abstract="false"
@@ -20274,6 +20252,17 @@
  visibility="public"
 >
 </method>
+<method name="isActivePasswordSufficient"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isAdminActive"
  return="boolean"
  abstract="false"
@@ -20287,6 +20276,17 @@
 <parameter name="who" type="android.content.ComponentName">
 </parameter>
 </method>
+<method name="lockNow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="removeActiveAdmin"
  return="void"
  abstract="false"
@@ -20300,6 +20300,19 @@
 <parameter name="who" type="android.content.ComponentName">
 </parameter>
 </method>
+<method name="resetPassword"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="password" type="java.lang.String">
+</parameter>
+</method>
 <method name="setMaximumTimeToLock"
  return="void"
  abstract="false"
@@ -20395,7 +20408,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="2000"
+ value="3000"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -20406,6 +20419,17 @@
  type="int"
  transient="false"
  volatile="false"
+ value="2000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_MODE_SOMETHING"
+ type="int"
+ transient="false"
+ volatile="false"
  value="1000"
  static="true"
  final="true"
@@ -20424,28 +20448,6 @@
  visibility="public"
 >
 </field>
-<field name="WIPE_EXTERNAL_STORAGE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="WIPE_LOW_LEVEL_FORMAT"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="Dialog"
  extends="java.lang.Object"
@@ -53548,6 +53550,17 @@
 <parameter name="stroke" type="android.gesture.GestureStroke">
 </parameter>
 </method>
+<method name="clone"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -54737,6 +54750,17 @@
 <parameter name="t" type="long">
 </parameter>
 </constructor>
+<method name="clone"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <field name="timestamp"
  type="long"
  transient="false"
@@ -55061,6 +55085,17 @@
  visibility="public"
 >
 </method>
+<method name="clone"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="computeOrientedBoundingBox"
  return="android.gesture.OrientedBoundingBox"
  abstract="false"
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index 4fdfe0a..538ba5b 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -79,9 +79,10 @@
      * Activity action: have the user enter a new password.  This activity
      * should be launched after using {@link #setPasswordMode(ComponentName, int)}
      * or {@link #setMinimumPasswordLength(ComponentName, int)} to have the
-     * user enter a new password that meets the current requirements.  If the
-     * current password is sufficient, the activity will exit immediately without
-     * being displayed to the user.  Upon receiving a result from this activity,
+     * 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.
      */
@@ -122,21 +123,31 @@
     
     /**
      * Constant for {@link #setPasswordMode}: the policy has no requirements
-     * for the password.
+     * for the password.  Note that mode constants are ordered so that higher
+     * values are more restrictive.
      */
     public static final int PASSWORD_MODE_UNSPECIFIED = 0;
     
     /**
-     * Constant for {@link #setPasswordMode}: the user must have at least a
-     * numeric password.
+     * Constant for {@link #setPasswordMode}: the policy requires some kind
+     * of password, but doesn't care what it is.  Note that mode constants
+     * are ordered so that higher values are more restrictive.
      */
-    public static final int PASSWORD_MODE_NUMERIC = 1000;
+    public static final int PASSWORD_MODE_SOMETHING = 1000;
+    
+    /**
+     * 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.
+     */
+    public static final int PASSWORD_MODE_NUMERIC = 2000;
     
     /**
      * Constant for {@link #setPasswordMode}: the user must have at least an
-     * alphanumeric password.
+     * alphanumeric password.  Note that mode constants are ordered so that higher
+     * values are more restrictive.
      */
-    public static final int PASSWORD_MODE_ALPHANUMERIC = 2000;
+    public static final int PASSWORD_MODE_ALPHANUMERIC = 3000;
     
     /**
      * Called by an application that is administering the device to set the
@@ -147,10 +158,15 @@
      * 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,
+     * the user's preference, and any other considerations) is the one that
+     * is in effect.
+     * 
      * @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_NUMERIC},
-     * or {@link #PASSWORD_MODE_ALPHANUMERIC}.
+     * {@link #PASSWORD_MODE_UNSPECIFIED}, {@link #PASSWORD_MODE_SOMETHING},
+     * {@link #PASSWORD_MODE_NUMERIC}, or {@link #PASSWORD_MODE_ALPHANUMERIC}.
      */
     public void setPasswordMode(ComponentName admin, int mode) {
         if (mService != null) {
@@ -178,21 +194,6 @@
     }
     
     /**
-     * Retrieve the password mode associated with the last password the
-     * user selected.
-     */
-    public int getActivePasswordMode() {
-        if (mService != null) {
-            try {
-                return mService.getActivePasswordMode();
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
-            }
-        }
-        return PASSWORD_MODE_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
@@ -234,18 +235,22 @@
     }
     
     /**
-     * Retrieve the password length associated with the last password the
-     * user selected.
+     * Determine whether the current password the user has set is sufficient
+     * to meet the policy requirements (mode, minimum length) that have been
+     * requested.
+     * 
+     * @return Returns true if the password meets the current requirements,
+     * else false.
      */
-    public int getActiveMinimumPasswordLength() {
+    public boolean isActivePasswordSufficient() {
         if (mService != null) {
             try {
-                return mService.getActiveMinimumPasswordLength();
+                return mService.isActivePasswordSufficient();
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
         }
-        return 0;
+        return false;
     }
     
     /**
@@ -262,6 +267,30 @@
         }
         return -1;
     }
+
+    /**
+     * 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.  (The string you give here is acceptable for any mode;
+     * if it contains only digits, that is still an acceptable alphanumeric
+     * password.)
+     * 
+     * @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.
+     */
+    public boolean resetPassword(String password) {
+        if (mService != null) {
+            try {
+                return mService.resetPassword(password);
+            } 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
@@ -298,22 +327,25 @@
     }
     
     /**
-     * Constant for {@link #wipeData}: perform a low-level format of data
-     * storage.
+     * Make the device lock immediately, as if the lock screen timeout has
+     * expired at the point of this call.
      */
-    public static final int WIPE_LOW_LEVEL_FORMAT = 0x0001;
-    
-    /**
-     * Constant for {@link #wipeData}: also wipe any external storage.
-     */
-    public static final int WIPE_EXTERNAL_STORAGE = 0x0002;
+    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.
+     * erasing all user data while next booting up.  External storage such
+     * as SD cards will not be erased.
      * 
-     * @param flags Bit mask of additional options: currently
-     * {@link #WIPE_LOW_LEVEL_FORMAT} and {@link #WIPE_EXTERNAL_STORAGE}.
+     * @param flags Bit mask of additional options: currently must be 0.
      */
     public void wipeData(int flags) {
         if (mService != null) {
diff --git a/core/java/android/app/IDevicePolicyManager.aidl b/core/java/android/app/IDevicePolicyManager.aidl
index f62647f..7e38194 100644
--- a/core/java/android/app/IDevicePolicyManager.aidl
+++ b/core/java/android/app/IDevicePolicyManager.aidl
@@ -26,17 +26,20 @@
 interface IDevicePolicyManager {
     void setPasswordMode(in ComponentName who, int mode);
     int getPasswordMode();
-    int getActivePasswordMode();
     
     void setMinimumPasswordLength(in ComponentName who, int length);
     int getMinimumPasswordLength();
-    int getActiveMinimumPasswordLength();
     
+    boolean isActivePasswordSufficient();
     int getCurrentFailedPasswordAttempts();
     
+    boolean resetPassword(String password);
+    
     void setMaximumTimeToLock(in ComponentName who, long timeMs);
     long getMaximumTimeToLock();
     
+    void lockNow();
+    
     void wipeData(int flags);
     
     void setActiveAdmin(in ComponentName policyReceiver);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 23762ca..b5408ae 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -28,6 +28,7 @@
     void setPokeLock(int pokey, IBinder lock, String tag);
     int getSupportedWakeLockFlags();
     void setStayOnSetting(int val);
+    void setMaximumScreenOffTimeount(int timeMs);
     void preventScreenOn(boolean prevent);
     boolean isScreenOn();
     void reboot(String reason);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 9f7a370..66c0719 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -79,9 +79,9 @@
      * pin = digit-only password
      * password = alphanumeric password
      */
-    public static final int MODE_PATTERN = 0;
-    public static final int MODE_PIN = 1;
-    public static final int MODE_PASSWORD = 2;
+    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;
 
     /**
      * The minimum number of dots the user must include in a wrong pattern
@@ -95,6 +95,7 @@
     private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
 
+    private final Context mContext;
     private final ContentResolver mContentResolver;
     private DevicePolicyManager mDevicePolicyManager;
     private static String sLockPatternFilename;
@@ -104,6 +105,7 @@
      * @param contentResolver Used to look up and save settings.
      */
     public LockPatternUtils(Context context) {
+        mContext = context;
         mContentResolver = context.getContentResolver();
         mDevicePolicyManager =
                 (DevicePolicyManager)context.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -126,10 +128,6 @@
         return mDevicePolicyManager.getMinimumPasswordLength();
     }
 
-    public int getActiveMinimumPasswordLength() {
-        return mDevicePolicyManager.getActiveMinimumPasswordLength();
-    }
-
     /**
      * Gets the device policy password mode. If the mode is non-specific, returns
      * MODE_PATTERN which allows the user to choose anything.
@@ -154,10 +152,6 @@
      *
      * @return
      */
-    public int getActivePasswordMode() {
-        return mDevicePolicyManager.getActivePasswordMode();
-    }
-
     public void reportFailedPasswordAttempt() {
         mDevicePolicyManager.reportFailedPasswordAttempt();
     }
@@ -279,6 +273,16 @@
     }
 
     /**
+     * Clear any lock pattern or password.
+     */
+    public void clearLock() {
+        saveLockPassword(null, LockPatternUtils.MODE_PATTERN);
+        setLockPatternEnabled(false);
+        saveLockPattern(null);
+        setLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
+    }
+    
+    /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
      */
@@ -295,11 +299,13 @@
                 raf.write(hash, 0, hash.length);
             }
             raf.close();
-            setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
-            setLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
-            if (pattern != null && isDevicePolicyActive()) {
-                setActivePasswordState(DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED,
-                        pattern.size());
+            if (pattern != null) {
+                setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
+                setLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
+                DevicePolicyManager dpm = (DevicePolicyManager)mContext.getSystemService(
+                        Context.DEVICE_POLICY_SERVICE);
+                dpm.setActivePasswordState(
+                        DevicePolicyManager.PASSWORD_MODE_SOMETHING, pattern.size());
             }
         } catch (FileNotFoundException fnfe) {
             // Cant do much, unless we want to fail over to using the settings provider
@@ -314,9 +320,8 @@
      * Save a lock password.
      * @param password The password to save
      */
-    public void saveLockPassword(String password) {
+    public void saveLockPassword(String password, int mode) {
         // Compute the hash
-        boolean numericHint = password != null ? TextUtils.isDigitsOnly(password) : false;
         final byte[] hash  = LockPatternUtils.passwordToHash(password);
         try {
             // Write the hash to file
@@ -328,10 +333,15 @@
                 raf.write(hash, 0, hash.length);
             }
             raf.close();
-            setLong(PASSWORD_TYPE_KEY, numericHint ? MODE_PIN : MODE_PASSWORD);
-            if (password != null && isDevicePolicyActive()) {
-                setActivePasswordState(numericHint ? DevicePolicyManager.PASSWORD_MODE_NUMERIC
-                    : DevicePolicyManager.PASSWORD_MODE_ALPHANUMERIC, password.length());
+            if (password != null) {
+                int textMode = TextUtils.isDigitsOnly(password) ? MODE_PIN : MODE_PASSWORD;
+                if (textMode > mode) {
+                    mode = textMode;
+                }
+                setLong(PASSWORD_TYPE_KEY, mode);
+                DevicePolicyManager dpm = (DevicePolicyManager)mContext.getSystemService(
+                        Context.DEVICE_POLICY_SERVICE);
+                dpm.setActivePasswordState(mode, password.length());
             }
         } catch (FileNotFoundException fnfe) {
             // Cant do much, unless we want to fail over to using the settings provider
@@ -554,6 +564,7 @@
     }
 
     private boolean getBoolean(String systemSettingKey) {
+        // STOPSHIP: these need to be moved to secure settings!
         return 1 ==
                 android.provider.Settings.System.getInt(
                         mContentResolver,
@@ -561,6 +572,7 @@
     }
 
     private void setBoolean(String systemSettingKey, boolean enabled) {
+        // STOPSHIP: these need to be moved to secure settings!
         android.provider.Settings.System.putInt(
                         mContentResolver,
                         systemSettingKey,
@@ -568,10 +580,12 @@
     }
 
     private long getLong(String systemSettingKey, long def) {
+        // STOPSHIP: these need to be moved to secure settings!
         return android.provider.Settings.System.getLong(mContentResolver, systemSettingKey, def);
     }
 
     private void setLong(String systemSettingKey, long value) {
+        // STOPSHIP: these need to be moved to secure settings!
         android.provider.Settings.System.putLong(mContentResolver, systemSettingKey, value);
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 89d75b7..979955c 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 = 46;
+    private static final int DATABASE_VERSION = 47;
 
     private Context mContext;
 
@@ -580,6 +580,21 @@
             upgradeVersion = 46;
         }
 
+        if (upgradeVersion == 46) {
+            /*
+             * The password mode constants have changed; reset back to no
+             * password.
+             */
+            db.beginTransaction();
+            try {
+                db.execSQL("DELETE FROM system WHERE name='lockscreen.password_type';");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+           upgradeVersion = 47;
+       }
+
 
         if (upgradeVersion != currentVersion) {
             Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index e13ddc8..fd42538 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import com.android.common.FastXmlSerializer;
+import com.android.internal.widget.LockPatternUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -27,11 +28,19 @@
 import android.app.DevicePolicyManager;
 import android.app.IDevicePolicyManager;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.PowerManager;
+import android.os.RecoverySystem;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.Xml;
 
@@ -49,6 +58,8 @@
     
     private final Context mContext;
 
+    IPowerManager mIPowerManager;
+    
     int mActivePasswordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
     int mActivePasswordLength = 0;
     int mFailedPasswordAttempts = 0;
@@ -75,8 +86,16 @@
         mContext = context;
     }
 
+    private IPowerManager getIPowerManager() {
+        if (mIPowerManager == null) {
+            IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
+            mIPowerManager = IPowerManager.Stub.asInterface(b);
+        }
+        return mIPowerManager;
+    }
+    
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException {
-        if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingPid()) {
+        if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingUid()) {
             if (who != null) {
                 if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName)
                         || !who.getClassName().equals(mActiveAdmin.info.getActivityInfo().name)) {
@@ -258,6 +277,17 @@
         if (!success) {
             Log.w(TAG, "No valid start tag found in policies file");
         }
+        
+        long timeMs = getMaximumTimeToLock();
+        if (timeMs <= 0) {
+            timeMs = Integer.MAX_VALUE;
+        }
+        try {
+            getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failure talking with power manager", e);
+        }
+        
     }
 
     public void systemReady() {
@@ -335,15 +365,6 @@
         }
     }
     
-    public int getActivePasswordMode() {
-        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);
-            return mActivePasswordMode;
-        }
-    }
-    
     public void setMinimumPasswordLength(ComponentName who, int length) {
         synchronized (this) {
             if (who == null) {
@@ -363,12 +384,13 @@
         }
     }
     
-    public int getActiveMinimumPasswordLength() {
+    public boolean isActivePasswordSufficient() {
         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);
-            return mActivePasswordLength;
+            return mActivePasswordMode >= getPasswordMode()
+                    && mActivePasswordLength >= getMinimumPasswordLength();
         }
     }
     
@@ -381,6 +403,31 @@
         }
     }
     
+    public boolean resetPassword(String password) {
+        int mode;
+        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);
+            mode = getPasswordMode();
+            if (password.length() < getMinimumPasswordLength()) {
+                return false;
+            }
+        }
+        
+        // Don't do this with the lock held, because it is going to call
+        // back in to the service.
+        long ident = Binder.clearCallingIdentity();
+        try {
+            LockPatternUtils utils = new LockPatternUtils(mContext);
+            utils.saveLockPassword(password, mode);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        
+        return true;
+    }
+    
     public void setMaximumTimeToLock(ComponentName who, long timeMs) {
         synchronized (this) {
             if (who == null) {
@@ -389,7 +436,21 @@
             ActiveAdmin ap = getActiveAdminForCallerLocked(who);
             if (ap.maximumTimeToUnlock != timeMs) {
                 ap.maximumTimeToUnlock = timeMs;
-                saveSettingsLocked();
+                
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    saveSettingsLocked();
+                    if (timeMs <= 0) {
+                        timeMs = Integer.MAX_VALUE;
+                    }
+                    try {
+                        getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failure talking with power manager", e);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
         }
     }
@@ -400,17 +461,28 @@
         }
     }
     
+    public void lockNow() {
+        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);
+            // STOPSHIP need to implement.
+        }
+    }
+    
     public void wipeData(int flags) {
         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);
-            long ident = Binder.clearCallingIdentity();
-            try {
-                Log.w(TAG, "*************** WIPE DATA HERE");
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+        }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            RecoverySystem.rebootWipeUserData(mContext);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed requesting data wipe", e);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
     
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index bf6996c..f106fc3 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -169,7 +169,8 @@
     private boolean mProximitySensorActive = false;
     private int mProximityPendingValue = -1; // -1 == nothing, 0 == inactive, 1 == active
     private long mLastProximityEventTime;
-    private int mTotalDelaySetting;
+    private int mScreenOffTimeoutSetting;
+    private int mMaximumScreenOffTimeout = Integer.MAX_VALUE;
     private int mKeylightDelay;
     private int mDimDelay;
     private int mScreenOffDelay;
@@ -378,6 +379,16 @@
                 Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
     }
 
+    public void setMaximumScreenOffTimeount(int timeMs) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
+        synchronized (mLocks) {
+            mMaximumScreenOffTimeout = timeMs;
+            // recalculate everything
+            setScreenOffTimeoutsLocked();
+        }
+    }
+
     private class SettingsObserver implements Observer {
         private int getInt(String name) {
             return mSettings.getValues(name).getAsInteger(Settings.System.VALUE);
@@ -390,7 +401,7 @@
                 updateWakeLockLocked();
 
                 // SCREEN_OFF_TIMEOUT
-                mTotalDelaySetting = getInt(SCREEN_OFF_TIMEOUT);
+                mScreenOffTimeoutSetting = getInt(SCREEN_OFF_TIMEOUT);
 
                  // DIM_SCREEN
                 //mDimScreen = getInt(DIM_SCREEN) != 0;
@@ -935,7 +946,8 @@
         pw.println("  mPreventScreenOn=" + mPreventScreenOn
                 + "  mScreenBrightnessOverride=" + mScreenBrightnessOverride
                 + "  mButtonBrightnessOverride=" + mButtonBrightnessOverride);
-        pw.println("  mTotalDelaySetting=" + mTotalDelaySetting);
+        pw.println("  mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting
+                + " mMaximumScreenOffTimeout=" + mMaximumScreenOffTimeout);
         pw.println("  mLastScreenOnTime=" + mLastScreenOnTime);
         pw.println("  mBroadcastWakeLock=" + mBroadcastWakeLock);
         pw.println("  mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
@@ -2285,7 +2297,10 @@
             mDimDelay = -1;
             mScreenOffDelay = 0;
         } else {
-            int totalDelay = mTotalDelaySetting;
+            int totalDelay = mScreenOffTimeoutSetting;
+            if (totalDelay > mMaximumScreenOffTimeout) {
+                totalDelay = mMaximumScreenOffTimeout;
+            }
             mKeylightDelay = LONG_KEYLIGHT_DELAY;
             if (totalDelay < 0) {
                 mScreenOffDelay = Integer.MAX_VALUE;