First pass at new device policy and administration APIs.

This adds new DevicAdmin, DevicePolicyManager, and DeviceAdminInfo classes.
See the java docs for each on documentation on them.  Basically: a DeviceAdmin
is what you derive from to administer a device; DevicePolicyManager is what you
use to apply and check your policy requirements and perform other administration
tasks.
diff --git a/Android.mk b/Android.mk
index ded8173..7c7bb62 100644
--- a/Android.mk
+++ b/Android.mk
@@ -75,6 +75,7 @@
 	core/java/android/app/IActivityWatcher.aidl \
 	core/java/android/app/IAlarmManager.aidl \
 	core/java/android/app/IBackupAgent.aidl \
+    core/java/android/app/IDevicePolicyManager.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
 	core/java/android/app/INotificationManager.aidl \
 	core/java/android/app/ISearchManager.aidl \
diff --git a/api/current.xml b/api/current.xml
index b690e42..ee7d330 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -177,6 +177,17 @@
  visibility="public"
 >
 </field>
+<field name="BIND_DEVICE_ADMIN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_DEVICE_ADMIN&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BIND_INPUT_METHOD"
  type="java.lang.String"
  transient="false"
@@ -188,6 +199,17 @@
  visibility="public"
 >
 </field>
+<field name="BIND_WALLPAPER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_WALLPAPER&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BLUETOOTH"
  type="java.lang.String"
  transient="false"
@@ -19831,6 +19853,600 @@
 </parameter>
 </method>
 </interface>
+<class name="DeviceAdmin"
+ extends="android.content.BroadcastReceiver"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeviceAdmin"
+ type="android.app.DeviceAdmin"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getManager"
+ return="android.app.DevicePolicyManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="getWho"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="onDisabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordFailed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordSucceeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onReceive"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<field name="ACTION_DEVICE_ADMIN_DISABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.DEVICE_ADMIN_DISABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DEVICE_ADMIN_ENABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.DEVICE_ADMIN_ENABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.ACTION_PASSWORD_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_FAILED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.ACTION_PASSWORD_FAILED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_SUCCEEDED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.ACTION_PASSWORD_SUCCEEDED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DEVICE_ADMIN_META_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.device_admin&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DeviceAdminInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="DeviceAdminInfo"
+ type="android.app.DeviceAdminInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="receiver" type="android.content.pm.ResolveInfo">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="XmlPullParserException" type="org.xmlpull.v1.XmlPullParserException">
+</exception>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="dump"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pw" type="android.util.Printer">
+</parameter>
+<parameter name="prefix" type="java.lang.String">
+</parameter>
+</method>
+<method name="getActivityInfo"
+ return="android.content.pm.ActivityInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getComponent"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPackageName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getReceiverName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="loadIcon"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pm" type="android.content.pm.PackageManager">
+</parameter>
+</method>
+<method name="loadLabel"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pm" type="android.content.pm.PackageManager">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DevicePolicyManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ 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"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaximumTimeToLock"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMinimumPasswordLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPasswordMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isAdminActive"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="who" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="removeActiveAdmin"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="who" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="setMaximumTimeToLock"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="timeMs" type="long">
+</parameter>
+</method>
+<method name="setMinimumPasswordLength"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setPasswordMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<method name="wipeData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="ACTION_ADD_DEVICE_ADMIN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.ADD_DEVICE_ADMIN&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_SET_NEW_PASSWORD"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.SET_NEW_PASSWORD&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DEVICE_ADMIN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.extra.DEVICE_ADMIN&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_MODE_ALPHANUMERIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_MODE_NUMERIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_MODE_UNSPECIFIED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ 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"
  abstract="false"
@@ -32576,6 +33192,17 @@
  visibility="public"
 >
 </field>
+<field name="DEVICE_POLICY_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;device_policy&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="DROPBOX_SERVICE"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index d89b877..fe05393 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -186,6 +186,7 @@
     private boolean mRestricted;
     private AccountManager mAccountManager; // protected by mSync
     private DropBoxManager mDropBoxManager = null;
+    private DevicePolicyManager mDevicePolicyManager = null;
 
     private final Object mSync = new Object();
 
@@ -895,6 +896,8 @@
             return getWallpaperManager();
         } else if (DROPBOX_SERVICE.equals(name)) {
             return getDropBoxManager();
+        } else if (DEVICE_POLICY_SERVICE.equals(name)) {
+            return getDevicePolicyManager();
         }
 
         return null;
@@ -1064,6 +1067,16 @@
         return mDropBoxManager;
     }
 
+    private DevicePolicyManager getDevicePolicyManager() {
+        synchronized (mSync) {
+            if (mDevicePolicyManager == null) {
+                mDevicePolicyManager = new DevicePolicyManager(this,
+                        mMainThread.getHandler());
+            }
+        }
+        return mDevicePolicyManager;
+    }
+
     @Override
     public int checkPermission(String permission, int pid, int uid) {
         if (permission == null) {
diff --git a/core/java/android/app/DeviceAdmin.java b/core/java/android/app/DeviceAdmin.java
new file mode 100644
index 0000000..4da3fee
--- /dev/null
+++ b/core/java/android/app/DeviceAdmin.java
@@ -0,0 +1,221 @@
+/*
+ * 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;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * 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>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>
+ * 
+ * <pre>{@include development/samples/ApiDemos/AndroidManifest.xml
+ *   device_admin_declaration}</pre>
+ *   
+ * <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>
+ * 
+ * <pre>{@include development/samples/ApiDemos/res/xml/sample_device_admin.xml
+ *   meta_data}</pre>
+ */
+public class DeviceAdmin 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 DeviceAdmin#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 disabled
+     * it.  Upon return, the application no longer has access to the
+     * protected device policy manager APIs.  You will generally
+     * handle this in {@link DeviceAdmin#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#getActivePasswordMode()
+     * DevicePolicyManager.getActivePasswordMode()} and
+     * {@link DevicePolicyManager#getActiveMinimumPasswordLength()
+     * DevicePolicyManager.getActiveMinimumPasswordLength()}.  You will generally
+     * handle this in {@link DeviceAdmin#onPasswordChanged(Context, Intent)}.
+     */
+    @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 DeviceAdmin#onPasswordFailed(Context, Intent)}.
+     */
+    @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.
+     */
+    @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 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_DISABLED.equals(action)) {
+            onDisabled(context, intent);
+        }
+    }
+}
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
new file mode 100644
index 0000000..eac6e46
--- /dev/null
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -0,0 +1,186 @@
+/*
+ * 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;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+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.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Printer;
+import android.util.Xml;
+
+import java.io.IOException;
+
+/**
+ * This class is used to specify meta information of a device administrator
+ * component.
+ */
+public final class DeviceAdminInfo implements Parcelable {
+    static final String TAG = "DeviceAdminInfo";
+    
+    /**
+     * The BroadcastReceiver that implements this device admin component.
+     */
+    final ResolveInfo mReceiver;
+    
+    /**
+     * 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, DeviceAdmin.DEVICE_ADMIN_META_DATA);
+            if (parser == null) {
+                throw new XmlPullParserException("No "
+                        + DeviceAdmin.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.Wallpaper);
+
+            sa.recycle();
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    DeviceAdminInfo(Parcel source) {
+        mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
+    }
+    
+    /**
+     * 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 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);
+    }
+    
+    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);
+    }
+
+    /**
+     * 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/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
new file mode 100644
index 0000000..4fdfe0a
--- /dev/null
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -0,0 +1,425 @@
+/*
+ * 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;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+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.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Public interface for managing policies enforced on a device.  Most clients
+ * of this class must have published a {@link DeviceAdmin} 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 Handler mHandler;
+    private final IDevicePolicyManager mService;
+
+    /*package*/ DevicePolicyManager(Context context, Handler handler) {
+        mContext = context;
+        mHandler = handler;
+        mService = IDevicePolicyManager.Stub.asInterface(
+                ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+    }
+
+    /**
+     * 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>Note: the current platform can only have one device administrator
+     * active at a time.  If you make this request while there is already
+     * an active administrator, this new request will be canceled automatically.
+     */
+    @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";
+    
+    /**
+     * 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,
+     * 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 who.equals(mService.getActiveAdmin());
+            } 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 #setPasswordMode}: the policy has no requirements
+     * for the password.
+     */
+    public static final int PASSWORD_MODE_UNSPECIFIED = 0;
+    
+    /**
+     * Constant for {@link #setPasswordMode}: the user must have at least a
+     * numeric password.
+     */
+    public static final int PASSWORD_MODE_NUMERIC = 1000;
+    
+    /**
+     * Constant for {@link #setPasswordMode}: the user must have at least an
+     * alphanumeric password.
+     */
+    public static final int PASSWORD_MODE_ALPHANUMERIC = 2000;
+    
+    /**
+     * 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.
+     * 
+     * @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}.
+     */
+    public void setPasswordMode(ComponentName admin, int mode) {
+        if (mService != null) {
+            try {
+                mService.setPasswordMode(admin, mode);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Retrieve the current password mode that is in effect due to all
+     * device admins.
+     */
+    public int getPasswordMode() {
+        if (mService != null) {
+            try {
+                return mService.getPasswordMode();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return PASSWORD_MODE_UNSPECIFIED;
+    }
+    
+    /**
+     * 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
+     * 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_MODE_NUMERIC} or {@link #PASSWORD_MODE_ALPHANUMERIC}
+     * with {@link #setPasswordMode}.
+     * 
+     * @param admin Which {@link DeviceAdmin} this request is associated with.
+     * @param length The new desired minimum password length.  A value of 0
+     * means there is no restriction.
+     */
+    public void setMinimumPasswordLength(ComponentName admin, int length) {
+        if (mService != null) {
+            try {
+                mService.setMinimumPasswordLength(admin, length);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
+     * Retrieve the current minimum password length that is in effect due to all
+     * device admins.
+     */
+    public int getMinimumPasswordLength() {
+        if (mService != null) {
+            try {
+                return mService.getMinimumPasswordLength();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+    
+    /**
+     * Retrieve the password length associated with the last password the
+     * user selected.
+     */
+    public int getActiveMinimumPasswordLength() {
+        if (mService != null) {
+            try {
+                return mService.getActiveMinimumPasswordLength();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+    
+    /**
+     * Retrieve the number of times the user has failed at entering a
+     * password since that last successful password entry.
+     */
+    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;
+    }
+    
+    /**
+     * 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.
+     * 
+     * @param admin Which {@link DeviceAdmin} this request is associated with.
+     * @param timeMs The new desired maximum time to lock in milliseconds.
+     * A value of 0 means there is no restriction.
+     */
+    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 lock that is in effect due to all
+     * device admins.  Returns 0 if no maximum is set.
+     */
+    public long getMaximumTimeToLock() {
+        if (mService != null) {
+            try {
+                return mService.getMaximumTimeToLock();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+    
+    /**
+     * Constant for {@link #wipeData}: perform a low-level format of data
+     * storage.
+     */
+    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;
+    
+    /**
+     * Ask the user date be wiped.  This will cause the device to reboot,
+     * erasing all user data while next booting up.
+     * 
+     * @param flags Bit mask of additional options: currently
+     * {@link #WIPE_LOW_LEVEL_FORMAT} and {@link #WIPE_EXTERNAL_STORAGE}.
+     */
+    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 ComponentName getActiveAdmin() {
+        if (mService != null) {
+            try {
+                return mService.getActiveAdmin();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * @hide
+     */
+    public DeviceAdminInfo getActiveAdminInfo() {
+        ComponentName cn = getActiveAdmin();
+        if (cn == null) {
+            return null;
+        }
+        
+        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 setActivePasswordState(int mode, int length) {
+        if (mService != null) {
+            try {
+                mService.setActivePasswordState(mode, 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/IDevicePolicyManager.aidl b/core/java/android/app/IDevicePolicyManager.aidl
new file mode 100644
index 0000000..f62647f
--- /dev/null
+++ b/core/java/android/app/IDevicePolicyManager.aidl
@@ -0,0 +1,49 @@
+/*
+**
+** 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;
+
+import android.content.ComponentName;
+
+/**
+ * Internal IPC interface to the device policy service.
+ * {@hide}
+ */
+interface IDevicePolicyManager {
+    void setPasswordMode(in ComponentName who, int mode);
+    int getPasswordMode();
+    int getActivePasswordMode();
+    
+    void setMinimumPasswordLength(in ComponentName who, int length);
+    int getMinimumPasswordLength();
+    int getActiveMinimumPasswordLength();
+    
+    int getCurrentFailedPasswordAttempts();
+    
+    void setMaximumTimeToLock(in ComponentName who, long timeMs);
+    long getMaximumTimeToLock();
+    
+    void wipeData(int flags);
+    
+    void setActiveAdmin(in ComponentName policyReceiver);
+    ComponentName getActiveAdmin();
+    void removeActiveAdmin(in ComponentName policyReceiver);
+    
+    void setActivePasswordState(int mode, int length);
+    void reportFailedPasswordAttempt();
+    void reportSuccessfulPasswordAttempt();
+}
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 1034fab..1612ac9 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 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;
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0fafe5d..0b83f03 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1132,6 +1132,7 @@
      * you're running long tasks.
      */
     public static final String POWER_SERVICE = "power";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.view.WindowManager} for accessing the system's window
@@ -1141,6 +1142,7 @@
      * @see android.view.WindowManager
      */
     public static final String WINDOW_SERVICE = "window";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.view.LayoutInflater} for inflating layout resources in this
@@ -1150,6 +1152,7 @@
      * @see android.view.LayoutInflater
      */
     public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.accounts.AccountManager} for receiving intents at a
@@ -1159,6 +1162,7 @@
      * @see android.accounts.AccountManager
      */
     public static final String ACCOUNT_SERVICE = "account";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.app.ActivityManager} for interacting with the global
@@ -1168,6 +1172,7 @@
      * @see android.app.ActivityManager
      */
     public static final String ACTIVITY_SERVICE = "activity";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.app.AlarmManager} for receiving intents at a
@@ -1177,6 +1182,7 @@
      * @see android.app.AlarmManager
      */
     public static final String ALARM_SERVICE = "alarm";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.app.NotificationManager} for informing the user of
@@ -1186,6 +1192,7 @@
      * @see android.app.NotificationManager
      */
     public static final String NOTIFICATION_SERVICE = "notification";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.view.accessibility.AccessibilityManager} for giving the user
@@ -1195,6 +1202,7 @@
      * @see android.view.accessibility.AccessibilityManager
      */
     public static final String ACCESSIBILITY_SERVICE = "accessibility";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.app.NotificationManager} for controlling keyguard.
@@ -1203,6 +1211,7 @@
      * @see android.app.KeyguardManager
      */
     public static final String KEYGUARD_SERVICE = "keyguard";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.location.LocationManager} for controlling location
@@ -1212,6 +1221,7 @@
      * @see android.location.LocationManager
      */
     public static final String LOCATION_SERVICE = "location";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.app.SearchManager} for handling searches.
@@ -1220,6 +1230,7 @@
      * @see android.app.SearchManager
      */
     public static final String SEARCH_SERVICE = "search";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.hardware.SensorManager} for accessing sensors.
@@ -1228,6 +1239,7 @@
      * @see android.hardware.SensorManager
      */
     public static final String SENSOR_SERVICE = "sensor";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a
      * com.android.server.WallpaperService for accessing wallpapers.
@@ -1235,6 +1247,7 @@
      * @see #getSystemService
      */
     public static final String WALLPAPER_SERVICE = "wallpaper";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.os.Vibrator} for interacting with the vibration hardware.
@@ -1243,6 +1256,7 @@
      * @see android.os.Vibrator
      */
     public static final String VIBRATOR_SERVICE = "vibrator";
+    
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.app.StatusBarManager} for interacting with the status bar.
@@ -1340,6 +1354,15 @@
     public static final String DROPBOX_SERVICE = "dropbox";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a 
+     * {@link android.app.DevicePolicyManager} for working with global
+     * device policy management.
+     *
+     * @see #getSystemService
+     */
+    public static final String DEVICE_POLICY_SERVICE = "device_policy";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index fe3b149..eb48a0c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -20,6 +20,8 @@
 import com.android.internal.view.BaseIWindow;
 import com.android.internal.view.BaseSurfaceHolder;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
 import android.app.WallpaperManager;
 import android.content.BroadcastReceiver;
@@ -58,9 +60,13 @@
 public abstract class WallpaperService extends Service {
     /**
      * The {@link Intent} that must be declared as handled by the service.
+     * To be supported, the service must also require the
+     * {@link android.Manifest.permission#BIND_WALLPAPER} permission so
+     * that other applications can not abuse it.
      */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE =
-        "android.service.wallpaper.WallpaperService";
+            "android.service.wallpaper.WallpaperService";
 
     /**
      * Name under which a WallpaperService component publishes information
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index a5e0e94..2ddf5f8 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -16,6 +16,8 @@
 
 package android.view.inputmethod;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 import android.os.ResultReceiver;
@@ -54,9 +56,12 @@
     /**
      * This is the interface name that a service implementing an input
      * method should say that it supports -- that is, this is the action it
-     * uses for its intent filter.  (Note: this name is used because this
-     * interface should be moved to the view package.)
+     * uses for its intent filter.
+     * To be supported, the service must also require the
+     * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission so
+     * that other applications can not abuse it.
      */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.view.InputMethod";
     
     /**
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 37372c5..0ce70fa 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -50,6 +50,7 @@
      * Whether the children of this layout are baseline aligned.  Only applicable
      * if {@link #mOrientation} is horizontal.
      */
+    @ViewDebug.ExportedProperty
     private boolean mBaselineAligned = true;
 
     /**
@@ -59,6 +60,7 @@
      * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
      * with whether the children of this layout are baseline aligned.
      */
+    @ViewDebug.ExportedProperty
     private int mBaselineAlignedChildIndex = -1;
 
     /**
@@ -66,12 +68,30 @@
      * We'll calculate the baseline of this layout as we measure vertically; for
      * horizontal linear layouts, the offset of 0 is appropriate.
      */
+    @ViewDebug.ExportedProperty
     private int mBaselineChildTop = 0;
 
+    @ViewDebug.ExportedProperty
     private int mOrientation;
+    @ViewDebug.ExportedProperty(mapping = {
+            @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
+            @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
+            @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
+            @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
+            @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
+            @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
+            @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
+            @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
+            @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+            @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
+            @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
+            @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
+        })
     private int mGravity = Gravity.LEFT | Gravity.TOP;
+    @ViewDebug.ExportedProperty
     private int mTotalLength;
 
+    @ViewDebug.ExportedProperty
     private float mWeightSum;
 
     private int[] mMaxAscent;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c49a86a..d81476a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -927,21 +927,27 @@
         android:description="@string/permdesc_readInputState"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by input method services, to ensure that only the
-         system can bind to them. -->
+    <!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
+         to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_INPUT_METHOD"
         android:label="@string/permlab_bindInputMethod"
         android:description="@string/permdesc_bindInputMethod"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by wallpaper services, to ensure that only the
-         system can bind to them.
-         @hide Live Wallpaper -->
+    <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
+         to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_WALLPAPER"
         android:label="@string/permlab_bindWallpaper"
         android:description="@string/permdesc_bindWallpaper"
         android:protectionLevel="signatureOrSystem" />
 
+    <!-- Must be required by device administration receiver, to ensure that only the
+         system can interact with it. -->
+    <permission android:name="android.permission.BIND_DEVICE_ADMIN"
+        android:label="@string/permlab_bindDeviceAdmin"
+        android:description="@string/permdesc_bindDeviceAdmin"
+        android:protectionLevel="signature" />
+
     <!-- Allows low-level access to setting the orientation (actually
          rotation) of the screen.  Not for use by normal applications. -->
     <permission android:name="android.permission.SET_ORIENTATION"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 539db83..265dacd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -617,6 +617,12 @@
         interface of a wallpaper. Should never be needed for normal applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindDeviceAdmin">interact with a device admin</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
+        a device administrator. Should never be needed for normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setOrientation">change screen orientation</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setOrientation">Allows an application to change
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
new file mode 100644
index 0000000..e13ddc8
--- /dev/null
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -0,0 +1,471 @@
+/*
+ * 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 com.android.server;
+
+import com.android.common.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.app.DeviceAdmin;
+import android.app.DeviceAdminInfo;
+import android.app.DevicePolicyManager;
+import android.app.IDevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.util.Log;
+import android.util.Xml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Implementation of the device policy APIs.
+ */
+public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+    private static final String TAG = "DevicePolicyManagerService";
+    
+    private final Context mContext;
+
+    int mActivePasswordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+    int mActivePasswordLength = 0;
+    int mFailedPasswordAttempts = 0;
+    
+    ActiveAdmin mActiveAdmin;
+    
+    static class ActiveAdmin {
+        ActiveAdmin(DeviceAdminInfo _info) {
+            info = _info;
+        }
+        
+        final DeviceAdminInfo info;
+        int getUid() { return info.getActivityInfo().applicationInfo.uid; }
+        
+        int passwordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+        int minimumPasswordLength = 0;
+        long maximumTimeToUnlock = 0;
+    }
+    
+    /**
+     * Instantiates the service.
+     */
+    public DevicePolicyManagerService(Context context) {
+        mContext = context;
+    }
+
+    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException {
+        if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingPid()) {
+            if (who != null) {
+                if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName)
+                        || !who.getClassName().equals(mActiveAdmin.info.getActivityInfo().name)) {
+                    throw new SecurityException("Current admin is not " + who);
+                }
+            }
+            return mActiveAdmin;
+        }
+        throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid());
+    }
+    
+    
+    void sendAdminCommandLocked(ActiveAdmin policy, String action) {
+        Intent intent = new Intent(action);
+        intent.setComponent(policy.info.getComponent());
+        mContext.sendBroadcast(intent);
+    }
+    
+    ComponentName getActiveAdminLocked() {
+        if (mActiveAdmin != null) {
+            return mActiveAdmin.info.getComponent();
+        }
+        return null;
+    }
+    
+    void removeActiveAdminLocked(ComponentName adminReceiver) {
+        ComponentName cur = getActiveAdminLocked();
+        if (cur != null && cur.equals(adminReceiver)) {
+            sendAdminCommandLocked(mActiveAdmin,
+                    DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLED);
+            // XXX need to wait for it to complete.
+            mActiveAdmin = null;
+        }
+    }
+    
+    public DeviceAdminInfo findAdmin(ComponentName adminName) {
+        Intent resolveIntent = new Intent();
+        resolveIntent.setComponent(adminName);
+        List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
+                resolveIntent, PackageManager.GET_META_DATA);
+        if (infos == null || infos.size() <= 0) {
+            throw new IllegalArgumentException("Unknown admin: " + adminName);
+        }
+        
+        try {
+            return new DeviceAdminInfo(mContext, infos.get(0));
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Bad device admin requested: " + adminName, e);
+            return null;
+        } catch (IOException e) {
+            Log.w(TAG, "Bad device admin requested: " + adminName, e);
+            return null;
+        }
+    }
+    
+    private static JournaledFile makeJournaledFile() {
+        final String base = "/data/system/device_policies.xml";
+        return new JournaledFile(new File(base), new File(base + ".tmp"));
+    }
+
+    private void saveSettingsLocked() {
+        JournaledFile journal = makeJournaledFile();
+        FileOutputStream stream = null;
+        try {
+            stream = new FileOutputStream(journal.chooseForWrite(), false);
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(stream, "utf-8");
+            out.startDocument(null, true);
+
+            out.startTag(null, "policies");
+            
+            ActiveAdmin ap = mActiveAdmin;
+            if (ap != null) {
+                out.startTag(null, "admin");
+                out.attribute(null, "name", ap.info.getComponent().flattenToString());
+                if (ap.passwordMode != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
+                    out.startTag(null, "password-mode");
+                    out.attribute(null, "value", Integer.toString(ap.passwordMode));
+                    out.endTag(null, "password-mode");
+                    if (ap.minimumPasswordLength > 0) {
+                        out.startTag(null, "min-password-length");
+                        out.attribute(null, "value", Integer.toString(ap.minimumPasswordLength));
+                        out.endTag(null, "mn-password-length");
+                    }
+                }
+                if (ap.maximumTimeToUnlock != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
+                    out.startTag(null, "max-time-to-unlock");
+                    out.attribute(null, "value", Long.toString(ap.maximumTimeToUnlock));
+                    out.endTag(null, "max-time-to-unlock");
+                }
+                out.endTag(null, "admin");
+            }
+            out.endTag(null, "policies");
+
+            out.endDocument();
+            stream.close();
+            journal.commit();
+        } catch (IOException e) {
+            try {
+                if (stream != null) {
+                    stream.close();
+                }
+            } catch (IOException ex) {
+                // Ignore
+            }
+            journal.rollback();
+        }
+    }
+
+    private void loadSettingsLocked() {
+        JournaledFile journal = makeJournaledFile();
+        FileInputStream stream = null;
+        File file = journal.chooseForRead();
+        boolean success = false;
+        try {
+            stream = new FileInputStream(file);
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, null);
+
+            int type = parser.next();
+            while (type != XmlPullParser.START_TAG) {
+                type = parser.next();
+            }
+            String tag = parser.getName();
+            if ("policies".equals(tag)) {
+                ActiveAdmin ap = null;
+                do {
+                    type = parser.next();
+                    if (type == XmlPullParser.START_TAG) {
+                        tag = parser.getName();
+                        if (ap == null) {
+                            if ("admin".equals(tag)) {
+                                DeviceAdminInfo dai = findAdmin(
+                                        ComponentName.unflattenFromString(
+                                                parser.getAttributeValue(null, "name")));
+                                if (dai != null) {
+                                    ap = new ActiveAdmin(dai);
+                                }
+                            }
+                        } else if ("password-mode".equals(tag)) {
+                            ap.passwordMode = Integer.parseInt(
+                                    parser.getAttributeValue(null, "value"));
+                        } else if ("min-password-length".equals(tag)) {
+                            ap.minimumPasswordLength = Integer.parseInt(
+                                    parser.getAttributeValue(null, "value"));
+                        } else if ("max-time-to-unlock".equals(tag)) {
+                            ap.maximumTimeToUnlock = Long.parseLong(
+                                    parser.getAttributeValue(null, "value"));
+                        }
+                    } else if (type == XmlPullParser.END_TAG) {
+                        tag = parser.getName();
+                        if (ap != null && "admin".equals(tag)) {
+                            mActiveAdmin = ap;
+                            ap = null;
+                        }
+                    }
+                } while (type != XmlPullParser.END_DOCUMENT);
+                success = true;
+            }
+        } catch (NullPointerException e) {
+            Log.w(TAG, "failed parsing " + file + " " + e);
+        } catch (NumberFormatException e) {
+            Log.w(TAG, "failed parsing " + file + " " + e);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "failed parsing " + file + " " + e);
+        } catch (IOException e) {
+            Log.w(TAG, "failed parsing " + file + " " + e);
+        } catch (IndexOutOfBoundsException e) {
+            Log.w(TAG, "failed parsing " + file + " " + e);
+        }
+        try {
+            if (stream != null) {
+                stream.close();
+            }
+        } catch (IOException e) {
+            // Ignore
+        }
+
+        if (!success) {
+            Log.w(TAG, "No valid start tag found in policies file");
+        }
+    }
+
+    public void systemReady() {
+        synchronized (this) {
+            loadSettingsLocked();
+        }
+    }
+    
+    public void setActiveAdmin(ComponentName adminReceiver) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        
+        DeviceAdminInfo info = findAdmin(adminReceiver);
+        if (info == null) {
+            throw new IllegalArgumentException("Bad admin: " + adminReceiver);
+        }
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                ComponentName cur = getActiveAdminLocked();
+                if (cur != null && cur.equals(adminReceiver)) {
+                    throw new IllegalStateException("An admin is already set");
+                }
+                if (cur != null) {
+                    removeActiveAdminLocked(adminReceiver);
+                }
+                mActiveAdmin = new ActiveAdmin(info);
+                saveSettingsLocked();
+                sendAdminCommandLocked(mActiveAdmin,
+                        DeviceAdmin.ACTION_DEVICE_ADMIN_ENABLED);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+    
+    public ComponentName getActiveAdmin() {
+        synchronized (this) {
+            return getActiveAdminLocked();
+        }
+    }
+    
+    public void removeActiveAdmin(ComponentName adminReceiver) {
+        synchronized (this) {
+            if (mActiveAdmin == null || mActiveAdmin.getUid() != Binder.getCallingUid()) {
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+            }
+            long ident = Binder.clearCallingIdentity();
+            try {
+                removeActiveAdminLocked(adminReceiver);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+    
+    public void setPasswordMode(ComponentName who, int mode) {
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+            if (ap.passwordMode != mode) {
+                ap.passwordMode = mode;
+                saveSettingsLocked();
+            }
+        }
+    }
+    
+    public int getPasswordMode() {
+        synchronized (this) {
+            return mActiveAdmin != null ? mActiveAdmin.passwordMode
+                    : DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+        }
+    }
+    
+    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) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+            if (ap.minimumPasswordLength != length) {
+                ap.minimumPasswordLength = length;
+                saveSettingsLocked();
+            }
+        }
+    }
+    
+    public int getMinimumPasswordLength() {
+        synchronized (this) {
+            return mActiveAdmin != null ? mActiveAdmin.minimumPasswordLength : 0;
+        }
+    }
+    
+    public int getActiveMinimumPasswordLength() {
+        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;
+        }
+    }
+    
+    public int getCurrentFailedPasswordAttempts() {
+        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 mFailedPasswordAttempts;
+        }
+    }
+    
+    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+            if (ap.maximumTimeToUnlock != timeMs) {
+                ap.maximumTimeToUnlock = timeMs;
+                saveSettingsLocked();
+            }
+        }
+    }
+    
+    public long getMaximumTimeToLock() {
+        synchronized (this) {
+            return mActiveAdmin != null ? mActiveAdmin.maximumTimeToUnlock : 0;
+        }
+    }
+    
+    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);
+            }
+        }
+    }
+    
+    public void setActivePasswordState(int mode, int length) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        
+        synchronized (this) {
+            if (mActivePasswordMode != mode || mActivePasswordLength != length
+                    || mFailedPasswordAttempts != 0) {
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    mActivePasswordMode = mode;
+                    mActivePasswordLength = length;
+                    mFailedPasswordAttempts = 0;
+                    sendAdminCommandLocked(mActiveAdmin,
+                            DeviceAdmin.ACTION_PASSWORD_CHANGED);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+    
+    public void reportFailedPasswordAttempt() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                mFailedPasswordAttempts++;
+                sendAdminCommandLocked(mActiveAdmin,
+                        DeviceAdmin.ACTION_PASSWORD_FAILED);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+    
+    public void reportSuccessfulPasswordAttempt() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        
+        synchronized (this) {
+            if (mFailedPasswordAttempts != 0) {
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    mFailedPasswordAttempts = 0;
+                    sendAdminCommandLocked(mActiveAdmin,
+                            DeviceAdmin.ACTION_PASSWORD_SUCCEEDED);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 674ade9..6b3f433 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -201,6 +201,7 @@
             Log.e("System", "Failure starting core service", e);
         }
 
+        DevicePolicyManagerService devicePolicy = null;
         StatusBarService statusBar = null;
         InputMethodManagerService imm = null;
         AppWidgetService appWidget = null;
@@ -209,16 +210,25 @@
 
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
             try {
+                Log.i(TAG, "Device Policy");
+                devicePolicy = new DevicePolicyManagerService(context);
+                ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
+            } catch (Throwable e) {
+                Log.e(TAG, "Failure starting DevicePolicyService", e);
+            }
+
+            try {
                 Log.i(TAG, "Status Bar");
                 statusBar = new StatusBarService(context);
-                ServiceManager.addService("statusbar", statusBar);
+                ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting StatusBarService", e);
             }
 
             try {
                 Log.i(TAG, "Clipboard Service");
-                ServiceManager.addService("clipboard", new ClipboardService(context));
+                ServiceManager.addService(Context.CLIPBOARD_SERVICE,
+                        new ClipboardService(context));
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting Clipboard Service", e);
             }
@@ -280,14 +290,16 @@
 
             try {
                 Log.i(TAG, "Location Manager");
-                ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context));
+                ServiceManager.addService(Context.LOCATION_SERVICE,
+                        new LocationManagerService(context));
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting Location Manager", e);
             }
 
             try {
                 Log.i(TAG, "Search Service");
-                ServiceManager.addService( Context.SEARCH_SERVICE, new SearchManagerService(context) );
+                ServiceManager.addService(Context.SEARCH_SERVICE,
+                        new SearchManagerService(context));
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting Search Service", e);
             }
@@ -351,7 +363,8 @@
 
             try {
                 Log.i(TAG, "Backup Service");
-                ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
+                ServiceManager.addService(Context.BACKUP_SERVICE,
+                        new BackupManagerService(context));
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting Backup Service", e);
             }
@@ -391,6 +404,10 @@
 
         // It is now time to start up the app processes...
 
+        if (devicePolicy != null) {
+            devicePolicy.systemReady();
+        }
+
         if (notification != null) {
             notification.systemReady();
         }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 40d194c..843058c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8381,7 +8381,7 @@
                         ActivityInfo ai = ris.get(i).activityInfo;
                         intent.setComponent(new ComponentName(ai.packageName, ai.name));
                         IIntentReceiver finisher = null;
-                        if (i == 0) {
+                        if (i == ris.size()-1) {
                             finisher = new IIntentReceiver.Stub() {
                                 public void performReceive(Intent intent, int resultCode,
                                         String data, Bundle extras, boolean ordered,
@@ -8397,7 +8397,7 @@
                         Log.i(TAG, "Sending system update to: " + intent.getComponent());
                         broadcastIntentLocked(null, null, intent, null, finisher,
                                 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
-                        if (i == 0) {
+                        if (finisher != null) {
                             mWaitingUpdate = true;
                         }
                     }