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/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;