Merge "NativeDaemonConnector: fix doListCommand() to return *all* list elements"
diff --git a/api/current.xml b/api/current.xml
index 03e20fa4..cd200c1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -20148,6 +20148,34 @@
  visibility="public"
 >
 </method>
+<method name="getTagForPolicy"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policyIdent" type="int">
+</parameter>
+</method>
+<method name="loadDescription"
+ 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>
+<exception name="Resources.NotFoundException" type="android.content.res.Resources.NotFoundException">
+</exception>
+</method>
 <method name="loadIcon"
  return="android.graphics.drawable.Drawable"
  abstract="false"
@@ -20174,6 +20202,19 @@
 <parameter name="pm" type="android.content.pm.PackageManager">
 </parameter>
 </method>
+<method name="usesPolicy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policyIdent" type="int">
+</parameter>
+</method>
 <method name="writeToParcel"
  return="void"
  abstract="false"
@@ -20199,6 +20240,72 @@
  visibility="public"
 >
 </field>
+<field name="USES_POLICY_FORCE_LOCK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_LIMIT_PASSWORD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_LIMIT_UNLOCK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_RESET_PASSWORD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_WATCH_LOGIN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USES_POLICY_WIPE_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="DevicePolicyManager"
  extends="java.lang.Object"
@@ -41567,6 +41674,16 @@
  visibility="public"
 >
 </field>
+<field name="descriptionRes"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="enabled"
  type="boolean"
  transient="false"
@@ -131147,6 +131264,21 @@
 <parameter name="name" type="java.lang.String">
 </parameter>
 </method>
+<method name="isLocationProviderEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cr" type="android.content.ContentResolver">
+</parameter>
+<parameter name="provider" type="java.lang.String">
+</parameter>
+</method>
 <method name="putFloat"
  return="boolean"
  abstract="false"
@@ -131215,6 +131347,23 @@
 <parameter name="value" type="java.lang.String">
 </parameter>
 </method>
+<method name="setLocationProviderEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cr" type="android.content.ContentResolver">
+</parameter>
+<parameter name="provider" type="java.lang.String">
+</parameter>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
 <field name="ACCESSIBILITY_ENABLED"
  type="java.lang.String"
  transient="false"
@@ -132547,6 +132696,39 @@
  visibility="public"
 >
 </field>
+<field name="SCREEN_BRIGHTNESS_MODE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;screen_brightness_mode&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREEN_BRIGHTNESS_MODE_AUTOMATIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREEN_BRIGHTNESS_MODE_MANUAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCREEN_OFF_TIMEOUT"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/app/DeviceAdmin.java b/core/java/android/app/DeviceAdmin.java
index 16832db..9750d6e 100644
--- a/core/java/android/app/DeviceAdmin.java
+++ b/core/java/android/app/DeviceAdmin.java
@@ -82,6 +82,10 @@
      * {@link DevicePolicyManager#getMinimumPasswordLength()
      * DevicePolicyManager.getMinimumPasswordLength()}.  You will generally
      * handle this in {@link DeviceAdmin#onPasswordChanged(Context, Intent)}.
+     * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to receive
+     * this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PASSWORD_CHANGED
@@ -94,6 +98,10 @@
      * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
      * DevicePolicyManager.getCurrentFailedPasswordAttempts()}.  You will generally
      * handle this in {@link DeviceAdmin#onPasswordFailed(Context, Intent)}.
+     * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
+     * this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PASSWORD_FAILED
@@ -102,6 +110,10 @@
     /**
      * Action sent to a device administrator when the user has successfully
      * entered their password, after failing one or more times.
+     * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
+     * this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PASSWORD_SUCCEEDED
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
index eac6e46..92fdbc8 100644
--- a/core/java/android/app/DeviceAdminInfo.java
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -19,21 +19,28 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.R;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.content.res.Resources.NotFoundException;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.Printer;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
 
 /**
  * This class is used to specify meta information of a device administrator
@@ -43,11 +50,123 @@
     static final String TAG = "DeviceAdminInfo";
     
     /**
+     * A type of policy that this device admin can use: limit the passwords
+     * that the user can select, via {@link DevicePolicyManager#setPasswordMode}
+     * and {@link DevicePolicyManager#setMinimumPasswordLength}.
+     * 
+     * <p>To control this policy, the device admin must have a "limit-password"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_LIMIT_PASSWORD = 0;
+    
+    /**
+     * A type of policy that this device admin can use: able to watch login
+     * attempts from the user, via {@link DeviceAdmin#ACTION_PASSWORD_FAILED},
+     * {@link DeviceAdmin#ACTION_PASSWORD_SUCCEEDED}, and
+     * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts}.
+     * 
+     * <p>To control this policy, the device admin must have a "watch-login"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_WATCH_LOGIN = 1;
+
+    /**
+     * A type of policy that this device admin can use: able to reset the
+     * user's password via
+     * {@link DevicePolicyManager#resetPassword}.
+     * 
+     * <p>To control this policy, the device admin must have a "reset-password"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_RESET_PASSWORD = 2;
+
+    /**
+     * A type of policy that this device admin can use: able to limit the
+     * maximum lock timeout for the device via
+     * {@link DevicePolicyManager#setMaximumTimeToLock}.
+     * 
+     * <p>To control this policy, the device admin must have a "limit-unlock"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_LIMIT_UNLOCK = 3;
+
+    /**
+     * A type of policy that this device admin can use: able to force the device
+     * to lock via{@link DevicePolicyManager#lockNow}.
+     * 
+     * <p>To control this policy, the device admin must have a "force-lock"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_FORCE_LOCK = 4;
+
+    /**
+     * A type of policy that this device admin can use: able to factory
+     * reset the device, erasing all of the user's data, via
+     * {@link DevicePolicyManager#wipeData}.
+     * 
+     * <p>To control this policy, the device admin must have a "wipe-data"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_WIPE_DATA = 5;
+
+    /** @hide */
+    public static class PolicyInfo {
+        final public String tag;
+        final public int label;
+        final public int description;
+        
+        public PolicyInfo(String tagIn, int labelIn, int descriptionIn) {
+            tag = tagIn;
+            label = labelIn;
+            description = descriptionIn;
+        }
+    }
+    
+    static HashMap<String, Integer> sKnownPolicies = new HashMap<String, Integer>();
+    static SparseArray<PolicyInfo> sRevKnownPolicies = new SparseArray<PolicyInfo>();
+    
+    static {
+        sRevKnownPolicies.put(USES_POLICY_LIMIT_PASSWORD,
+                new PolicyInfo("limit-password",
+                        com.android.internal.R.string.policylab_limitPassword,
+                        com.android.internal.R.string.policydesc_limitPassword));
+        sRevKnownPolicies.put(USES_POLICY_WATCH_LOGIN,
+                new PolicyInfo("watch-login",
+                        com.android.internal.R.string.policylab_watchLogin,
+                        com.android.internal.R.string.policydesc_watchLogin));
+        sRevKnownPolicies.put(USES_POLICY_RESET_PASSWORD,
+                new PolicyInfo("reset-password",
+                        com.android.internal.R.string.policylab_resetPassword,
+                        com.android.internal.R.string.policydesc_resetPassword));
+        sRevKnownPolicies.put(USES_POLICY_LIMIT_UNLOCK,
+                new PolicyInfo("limit-unlock",
+                        com.android.internal.R.string.policylab_limitUnlock,
+                        com.android.internal.R.string.policydesc_limitUnlock));
+        sRevKnownPolicies.put(USES_POLICY_FORCE_LOCK,
+                new PolicyInfo("force-lock",
+                        com.android.internal.R.string.policylab_forceLock,
+                        com.android.internal.R.string.policydesc_forceLock));
+        sRevKnownPolicies.put(USES_POLICY_WIPE_DATA,
+                new PolicyInfo("wipe-data",
+                        com.android.internal.R.string.policylab_wipeData,
+                        com.android.internal.R.string.policydesc_wipeData));
+        for (int i=0; i<sRevKnownPolicies.size(); i++) {
+            sKnownPolicies.put(sRevKnownPolicies.valueAt(i).tag,
+                    sRevKnownPolicies.keyAt(i));
+        }
+    }
+    
+    /**
      * The BroadcastReceiver that implements this device admin component.
      */
     final ResolveInfo mReceiver;
     
     /**
+     * The policies this administrator needs access to.
+     */
+    int mUsesPolicies;
+    
+    /**
      * Constructor.
      * 
      * @param context The Context in which we are parsing the device admin.
@@ -86,6 +205,32 @@
                     com.android.internal.R.styleable.Wallpaper);
 
             sa.recycle();
+            
+            int outerDepth = parser.getDepth();
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+                String tagName = parser.getName();
+                if (tagName.equals("uses-policies")) {
+                    int innerDepth = parser.getDepth();
+                    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                           && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                            continue;
+                        }
+                        String policyName = parser.getName();
+                        Integer val = sKnownPolicies.get(policyName);
+                        if (val != null) {
+                            mUsesPolicies |= 1 << val.intValue();
+                        } else {
+                            Log.w(TAG, "Unknown tag under uses-policies of "
+                                    + getComponent() + ": " + policyName);
+                        }
+                    }
+                }
+            }
         } finally {
             if (parser != null) parser.close();
         }
@@ -93,6 +238,7 @@
 
     DeviceAdminInfo(Parcel source) {
         mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
+        mUsesPolicies = source.readInt();
     }
     
     /**
@@ -137,6 +283,26 @@
     }
     
     /**
+     * Load user-visible description associated with this device admin.
+     * 
+     * @param pm Supply a PackageManager used to load the device admin's
+     * resources.
+     */
+    public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
+        if (mReceiver.activityInfo.descriptionRes != 0) {
+            String packageName = mReceiver.resolvePackageName;
+            ApplicationInfo applicationInfo = null;
+            if (packageName == null) {
+                packageName = mReceiver.activityInfo.packageName;
+                applicationInfo = mReceiver.activityInfo.applicationInfo;
+            }
+            return pm.getText(packageName,
+                    mReceiver.activityInfo.descriptionRes, applicationInfo);
+        }
+        throw new NotFoundException();
+    }
+    
+    /**
      * Load the user-displayed icon for this device admin.
      * 
      * @param pm Supply a PackageManager used to load the device admin's
@@ -146,6 +312,38 @@
         return mReceiver.loadIcon(pm);
     }
     
+    /**
+     * Return true if the device admin has requested that it be able to use
+     * the given policy control.  The possible policy identifier inputs are:
+     * {@link #USES_POLICY_LIMIT_PASSWORD}, {@link #USES_POLICY_WATCH_LOGIN},
+     * {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_LIMIT_UNLOCK},
+     * {@link #USES_POLICY_FORCE_LOCK}, {@link #USES_POLICY_WIPE_DATA}.
+     */
+    public boolean usesPolicy(int policyIdent) {
+        return (mUsesPolicies & (1<<policyIdent)) != 0;
+    }
+    
+    /**
+     * Return the XML tag name for the given policy identifier.  Valid identifiers
+     * are as per {@link #usesPolicy(int)}.  If the given identifier is not
+     * known, null is returned.
+     */
+    public String getTagForPolicy(int policyIdent) {
+        return sRevKnownPolicies.get(policyIdent).tag;
+    }
+    
+    /** @hide */
+    public ArrayList<PolicyInfo> getUsedPolicies() {
+        ArrayList<PolicyInfo> res = new ArrayList<PolicyInfo>();
+        for (int i=0; i<sRevKnownPolicies.size(); i++) {
+            int ident = sRevKnownPolicies.keyAt(i);
+            if (usesPolicy(ident)) {
+                res.add(sRevKnownPolicies.valueAt(i));
+            }
+        }
+        return res;
+    }
+    
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "Receiver:");
         mReceiver.dump(pw, prefix + "  ");
@@ -164,6 +362,7 @@
      */
     public void writeToParcel(Parcel dest, int flags) {
         mReceiver.writeToParcel(dest, flags);
+        dest.writeInt(mUsesPolicies);
     }
 
     /**
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index 538ba5b..25e3230 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -163,6 +163,10 @@
      * the user's preference, and any other considerations) is the one that
      * is in effect.
      * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     * 
      * @param admin Which {@link DeviceAdmin} this request is associated with.
      * @param mode The new desired mode.  One of
      * {@link #PASSWORD_MODE_UNSPECIFIED}, {@link #PASSWORD_MODE_SOMETHING},
@@ -205,6 +209,10 @@
      * {@link #PASSWORD_MODE_NUMERIC} or {@link #PASSWORD_MODE_ALPHANUMERIC}
      * with {@link #setPasswordMode}.
      * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     * 
      * @param admin Which {@link DeviceAdmin} this request is associated with.
      * @param length The new desired minimum password length.  A value of 0
      * means there is no restriction.
@@ -239,6 +247,10 @@
      * to meet the policy requirements (mode, minimum length) that have been
      * requested.
      * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     * 
      * @return Returns true if the password meets the current requirements,
      * else false.
      */
@@ -256,6 +268,10 @@
     /**
      * Retrieve the number of times the user has failed at entering a
      * password since that last successful password entry.
+     * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call
+     * this method; if it has not, a security exception will be thrown.
      */
     public int getCurrentFailedPasswordAttempts() {
         if (mService != null) {
@@ -277,6 +293,10 @@
      * if it contains only digits, that is still an acceptable alphanumeric
      * password.)
      * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     * 
      * @param password The new password for the user.
      * @return Returns true if the password was applied, or false if it is
      * not acceptable for the current constraints.
@@ -297,6 +317,10 @@
      * maximum time for user activity until the device will lock.  This limits
      * the length that the user can set.  It takes effect immediately.
      * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_UNLOCK} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     * 
      * @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.
@@ -329,6 +353,10 @@
     /**
      * Make the device lock immediately, as if the lock screen timeout has
      * expired at the point of this call.
+     * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
+     * this method; if it has not, a security exception will be thrown.
      */
     public void lockNow() {
         if (mService != null) {
@@ -345,6 +373,10 @@
      * erasing all user data while next booting up.  External storage such
      * as SD cards will not be erased.
      * 
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     * 
      * @param flags Bit mask of additional options: currently must be 0.
      */
     public void wipeData(int flags) {
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 1612ac9..5ca3fb54 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -21,6 +21,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -204,7 +205,7 @@
 
         return pm.getDrawable(mService.serviceInfo.packageName,
                               mThumbnailResource,
-                              null);
+                              mService.serviceInfo.applicationInfo);
     }
 
     /**
@@ -212,25 +213,33 @@
      */
     public CharSequence loadAuthor(PackageManager pm) throws NotFoundException {
         if (mAuthorResource <= 0) throw new NotFoundException();
-        return pm.getText(
-            (mService.resolvePackageName != null)
-                ? mService.resolvePackageName
-                : getPackageName(),
-            mAuthorResource,
-            null);
+        String packageName = mService.resolvePackageName;
+        ApplicationInfo applicationInfo = null;
+        if (packageName == null) {
+            packageName = mService.serviceInfo.packageName;
+            applicationInfo = mService.serviceInfo.applicationInfo;
+        }
+        return pm.getText(packageName, mAuthorResource, applicationInfo);
     }
 
     /**
      * Return a brief summary of this wallpaper's behavior.
      */
     public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
+        String packageName = mService.resolvePackageName;
+        ApplicationInfo applicationInfo = null;
+        if (packageName == null) {
+            packageName = mService.serviceInfo.packageName;
+            applicationInfo = mService.serviceInfo.applicationInfo;
+        }
+        if (mService.serviceInfo.descriptionRes != 0) {
+            return pm.getText(packageName, mService.serviceInfo.descriptionRes,
+                    applicationInfo);
+            
+        }
         if (mDescriptionResource <= 0) throw new NotFoundException();
-        return pm.getText(
-            (mService.resolvePackageName != null)
-                ? mService.resolvePackageName
-                : getPackageName(),
-            mDescriptionResource,
-            null);
+        return pm.getText(packageName, mDescriptionResource,
+                mService.serviceInfo.applicationInfo);
     }
     
     /**
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index da1647a..0b27117 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -16,6 +16,7 @@
 
 package android.backup;
 
+import android.backup.RestoreSession;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -115,19 +116,21 @@
      *
      * {@hide}
      */
-    public IRestoreSession beginRestoreSession(String transport) {
+    public RestoreSession beginRestoreSession() {
         if (!EVEN_THINK_ABOUT_DOING_RESTORE) {
             return null;
         }
-        IRestoreSession binder = null;
+        RestoreSession session = null;
         checkServiceBinder();
         if (sService != null) {
             try {
-                binder = sService.beginRestoreSession(transport);
+                String transport = sService.getCurrentTransport();
+                IRestoreSession binder = sService.beginRestoreSession(transport);
+                session = new RestoreSession(mContext, binder);
             } catch (RemoteException e) {
                 Log.d(TAG, "beginRestoreSession() couldn't connect");
             }
         }
-        return binder;
+        return session;
     }
 }
diff --git a/core/java/android/backup/RestoreObserver.java b/core/java/android/backup/RestoreObserver.java
new file mode 100644
index 0000000..3be8c08
--- /dev/null
+++ b/core/java/android/backup/RestoreObserver.java
@@ -0,0 +1,53 @@
+/*
+ * 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.backup;
+
+/**
+ * Callback class for receiving progress reports during a restore operation.  These
+ * methods will all be called on your application's main thread.
+ * @hide
+ */
+public abstract class RestoreObserver {
+    /**
+     * The restore operation has begun.
+     *
+     * @param numPackages The total number of packages being processed in
+     *   this restore operation.
+     */
+    void restoreStarting(int numPackages) {
+    }
+
+    /**
+     * An indication of which package is being restored currently, out of the
+     * total number provided in the restoreStarting() callback.  This method
+     * is not guaranteed to be called.
+     *
+     * @param nowBeingRestored The index, between 1 and the numPackages parameter
+     *   to the restoreStarting() callback, of the package now being restored.
+     */
+    void onUpdate(int nowBeingRestored) {
+    }
+
+    /**
+     * The restore operation has completed.
+     *
+     * @param error Zero on success; a nonzero error code if the restore operation
+     *   as a whole failed.
+     */
+    void restoreFinished(int error) {
+    }
+}
diff --git a/core/java/android/backup/RestoreSession.java b/core/java/android/backup/RestoreSession.java
new file mode 100644
index 0000000..119fc52
--- /dev/null
+++ b/core/java/android/backup/RestoreSession.java
@@ -0,0 +1,178 @@
+/*
+ * 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.backup;
+
+import android.backup.IRestoreSession;
+import android.backup.RestoreObserver;
+import android.backup.RestoreSet;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Interface for applications to use when managing a restore session.
+ * @hide
+ */
+public class RestoreSession {
+    static final String TAG = "RestoreSession";
+
+    final Context mContext;
+    IRestoreSession mBinder;
+    RestoreObserverWrapper mObserver = null;
+
+    /**
+     * Ask the current transport what the available restore sets are.
+     *
+     * @return A bundle containing two elements:  an int array under the key
+     *   "tokens" whose entries are a transport-private identifier for each backup set;
+     *   and a String array under the key "names" whose entries are the user-meaningful
+     *   text corresponding to the backup sets at each index in the tokens array.
+     *   On error, returns null.
+     */
+    public RestoreSet[] getAvailableRestoreSets() {
+        try {
+            return mBinder.getAvailableRestoreSets();
+        } catch (RemoteException e) {
+            Log.d(TAG, "Can't contact server to get available sets");
+            return null;
+        }
+    }
+
+    /**
+     * Restore the given set onto the device, replacing the current data of any app
+     * contained in the restore set with the data previously backed up.
+     *
+     * @return Zero on success; nonzero on error.  The observer will only receive
+     *   progress callbacks if this method returned zero.
+     * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
+     *   the restore set that should be used.
+     * @param observer If non-null, this argument points to an object that will receive
+     *   progress callbacks during the restore operation. These callbacks will occur
+     *   on the main thread of the application.
+     */
+    public int performRestore(long token, RestoreObserver observer) {
+        int err = -1;
+        if (mObserver != null) {
+            Log.d(TAG, "performRestore() called during active restore");
+            return -1;
+        }
+        mObserver = new RestoreObserverWrapper(mContext, observer);
+        try {
+            err = mBinder.performRestore(token, mObserver);
+        } catch (RemoteException e) {
+            Log.d(TAG, "Can't contact server to perform restore");
+        }
+        return err;
+    }
+
+    /**
+     * End this restore session.  After this method is called, the RestoreSession
+     * object is no longer valid.
+     *
+     * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
+     *   even if {@link #getAvailableRestoreSets()} or
+     *   {@link #performRestore(long, RestoreObserver)} failed.
+     */
+    public void endRestoreSession() {
+        try {
+            mBinder.endRestoreSession();
+        } catch (RemoteException e) {
+            Log.d(TAG, "Can't contact server to get available sets");
+        } finally {
+            mBinder = null;
+        }
+    }
+
+    /*
+     * Nonpublic implementation here
+     */
+
+    RestoreSession(Context context, IRestoreSession binder) {
+        mContext = context;
+        mBinder = binder;
+    }
+
+    /*
+     * We wrap incoming binder calls with a private class implementation that
+     * redirects them into main-thread actions.  This accomplishes two things:
+     * first, it ensures that the app's code is run on their own main thread,
+     * never with system Binder identity; and second, it serializes the restore
+     * progress callbacks nicely within the usual main-thread lifecycle pattern.
+     */
+    private class RestoreObserverWrapper extends IRestoreObserver.Stub {
+        final Handler mHandler;
+        final RestoreObserver mAppObserver;
+
+        RestoreObserverWrapper(Context context, RestoreObserver appObserver) {
+            mHandler = new Handler(context.getMainLooper());
+            mAppObserver = appObserver;
+        }
+
+        // Wrap the IRestoreObserver -> RestoreObserver callthrough in Runnables
+        // posted to the app's main thread looper.
+        class RestoreStartingRunnable implements Runnable {
+            int mNumPackages;
+
+            RestoreStartingRunnable(int numPackages) {
+                mNumPackages = numPackages;
+            }
+
+            public void run() {
+                mAppObserver.restoreStarting(mNumPackages);
+            }
+        }
+
+        class OnUpdateRunnable implements Runnable {
+            int mNowRestoring;
+
+            OnUpdateRunnable(int nowRestoring) {
+                mNowRestoring = nowRestoring;
+            }
+
+            public void run() {
+                mAppObserver.onUpdate(mNowRestoring);
+            }
+        }
+
+        class RestoreFinishedRunnable implements Runnable {
+            int mError;
+
+            RestoreFinishedRunnable(int error) {
+                mError = error;
+            }
+
+            public void run() {
+                mAppObserver.restoreFinished(mError);
+            }
+        }
+
+        // The actual redirection code is quite simple using just the
+        // above Runnable subclasses
+        public void restoreStarting(int numPackages) {
+            mHandler.post(new RestoreStartingRunnable(numPackages));
+        }
+
+        public void onUpdate(int nowBeingRestored) {
+            mHandler.post(new OnUpdateRunnable(nowBeingRestored));
+        }
+
+        public void restoreFinished(int error) {
+            mHandler.post(new RestoreFinishedRunnable(error));
+        }
+    }
+}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a7ea507..808c839b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -234,6 +234,14 @@
     public static final int FLAG_ON_SDCARD = 1<<19;
 
     /**
+     * Value for {@link #flags}: Set to true if the application is
+     * native-debuggable, i.e. embeds a gdbserver binary in its .apk
+     *
+     * {@hide}
+     */
+    public static final int FLAG_NATIVE_DEBUGGABLE = 1<<20;
+
+    /**
      * Flags associated with the application.  Any combination of
      * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 73c9244..338c62b6 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2008 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.content.pm;
 
 import android.graphics.drawable.Drawable;
@@ -27,6 +43,13 @@
     public String processName;
 
     /**
+     * A string resource identifier (in the package's resources) containing
+     * a user-readable description of the component.  From the "description"
+     * attribute or, if not set, 0.
+     */
+    public int descriptionRes;
+    
+    /**
      * Indicates whether or not this component may be instantiated.  Note that this value can be
      * overriden by the one in its parent {@link ApplicationInfo}.
      */
@@ -47,6 +70,7 @@
         super(orig);
         applicationInfo = orig.applicationInfo;
         processName = orig.processName;
+        descriptionRes = orig.descriptionRes;
         enabled = orig.enabled;
         exported = orig.exported;
     }
@@ -108,6 +132,9 @@
         super.dumpFront(pw, prefix);
         pw.println(prefix + "enabled=" + enabled + " exported=" + exported
                 + " processName=" + processName);
+        if (descriptionRes != 0) {
+            pw.println(prefix + "description=" + descriptionRes);
+        }
     }
     
     protected void dumpBack(Printer pw, String prefix) {
@@ -124,6 +151,7 @@
         super.writeToParcel(dest, parcelableFlags);
         applicationInfo.writeToParcel(dest, parcelableFlags);
         dest.writeString(processName);
+        dest.writeInt(descriptionRes);
         dest.writeInt(enabled ? 1 : 0);
         dest.writeInt(exported ? 1 : 0);
     }
@@ -132,6 +160,7 @@
         super(source);
         applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
         processName = source.readString();
+        descriptionRes = source.readInt();
         enabled = (source.readInt() != 0);
         exported = (source.readInt() != 0);
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8a5df32..bbde0a6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -119,15 +119,18 @@
     static class ParseComponentArgs extends ParsePackageItemArgs {
         final String[] sepProcesses;
         final int processRes;
+        final int descriptionRes;
         final int enabledRes;
         int flags;
         
         ParseComponentArgs(Package _owner, String[] _outError,
                 int _nameRes, int _labelRes, int _iconRes,
-                String[] _sepProcesses, int _processRes,int _enabledRes) {
+                String[] _sepProcesses, int _processRes,
+                int _descriptionRes, int _enabledRes) {
             super(_owner, _outError, _nameRes, _labelRes, _iconRes);
             sepProcesses = _sepProcesses;
             processRes = _processRes;
+            descriptionRes = _descriptionRes;
             enabledRes = _enabledRes;
         }
     }
@@ -1602,6 +1605,7 @@
                     com.android.internal.R.styleable.AndroidManifestActivity_icon,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestActivity_process,
+                    com.android.internal.R.styleable.AndroidManifestActivity_description,
                     com.android.internal.R.styleable.AndroidManifestActivity_enabled);
         }
         
@@ -1803,6 +1807,7 @@
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
                     mSeparateProcesses,
                     0,
+                    com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
             mParseActivityAliasArgs.tag = "<activity-alias>";
         }
@@ -1837,6 +1842,9 @@
         info.nonLocalizedLabel = target.info.nonLocalizedLabel;
         info.launchMode = target.info.launchMode;
         info.processName = target.info.processName;
+        if (info.descriptionRes == 0) {
+            info.descriptionRes = target.info.descriptionRes;
+        }
         info.screenOrientation = target.info.screenOrientation;
         info.taskAffinity = target.info.taskAffinity;
         info.theme = target.info.theme;
@@ -1926,6 +1934,7 @@
                     com.android.internal.R.styleable.AndroidManifestProvider_icon,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestProvider_process,
+                    com.android.internal.R.styleable.AndroidManifestProvider_description,
                     com.android.internal.R.styleable.AndroidManifestProvider_enabled);
             mParseProviderArgs.tag = "<provider>";
         }
@@ -2188,6 +2197,7 @@
                     com.android.internal.R.styleable.AndroidManifestService_icon,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestService_process,
+                    com.android.internal.R.styleable.AndroidManifestService_description,
                     com.android.internal.R.styleable.AndroidManifestService_enabled);
             mParseServiceArgs.tag = "<service>";
         }
@@ -2640,6 +2650,11 @@
                         owner.applicationInfo.processName, args.sa.getNonResourceString(args.processRes),
                         args.flags, args.sepProcesses, args.outError);
             }
+            
+            if (args.descriptionRes != 0) {
+                outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
+            }
+            
             outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
         }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8172ac4..ecfea00 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1130,19 +1130,16 @@
 
         /**
          * Control whether to enable automatic brightness mode.
-         * @hide
          */
         public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
 
         /**
          * SCREEN_BRIGHTNESS_MODE value for manual mode.
-         * @hide
          */
         public static final int SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
 
         /**
          * SCREEN_BRIGHTNESS_MODE value for manual mode.
-         * @hide
          */
         public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
 
@@ -2977,8 +2974,6 @@
          * @param cr the content resolver to use
          * @param provider the location provider to query
          * @return true if the provider is enabled
-         *
-         * @hide
          */
         public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
             String allowedProviders = Settings.Secure.getString(cr, LOCATION_PROVIDERS_ALLOWED);
@@ -2996,8 +2991,6 @@
          * @param cr the content resolver to use
          * @param provider the location provider to enable or disable
          * @param enabled true if the provider should be enabled
-         *
-         * @hide
          */
         public static final void setLocationProviderEnabled(ContentResolver cr,
                 String provider, boolean enabled) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 56650a6..93e72ff 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4607,14 +4607,11 @@
                                 break;
                             }
                         } else {
-                            if (mPreventDrag == PREVENT_DRAG_MAYBE_YES) {
-                                // if mPreventDrag is not confirmed, treat it as
-                                // no so that it won't block tap or double tap.
-                                mPreventDrag = PREVENT_DRAG_NO;
-                                mPreventLongPress = false;
-                                mPreventDoubleTap = false;
-                            }
-                            if (mPreventDrag == PREVENT_DRAG_NO) {
+                            // mPreventDrag can be PREVENT_DRAG_MAYBE_YES in
+                            // TOUCH_INIT_MODE. To give WebCoreThread a little
+                            // more time to send PREVENT_TOUCH_ID, we check
+                            // again in responding RELEASE_SINGLE_TAP.
+                            if (mPreventDrag != PREVENT_DRAG_YES) {
                                 if (mTouchMode == TOUCH_INIT_MODE) {
                                     mPrivateHandler.sendMessageDelayed(
                                             mPrivateHandler.obtainMessage(
@@ -5631,6 +5628,13 @@
                     break;
                 }
                 case RELEASE_SINGLE_TAP: {
+                    if (mPreventDrag == PREVENT_DRAG_MAYBE_YES) {
+                        // if mPreventDrag is not confirmed, treat it as
+                        // no so that it won't block tap.
+                        mPreventDrag = PREVENT_DRAG_NO;
+                        mPreventLongPress = false;
+                        mPreventDoubleTap = false;
+                    }
                     if (mPreventDrag == PREVENT_DRAG_NO) {
                         mTouchMode = TOUCH_DONE_MODE;
                         doShortPress();
@@ -5863,7 +5867,7 @@
                         // updates is a C++ pointer to a Vector of
                         // AnimationValues that we apply to the layers.
                         // The Vector is deallocated in nativeUpdateLayers().
-                        nativeUpdateLayers(mRootLayer, updates);
+                        nativeUpdateLayers(updates);
                     }
                     invalidate();
                     break;
@@ -5985,10 +5989,22 @@
                         }
                         mFullScreenHolder = new PluginFullScreenHolder(
                                 WebView.this, data.mNpp);
+                        // as we are sharing the View between full screen and
+                        // embedded mode, we have to remove the
+                        // AbsoluteLayout.LayoutParams set by embedded mode to
+                        // ViewGroup.LayoutParams before adding it to the dialog
+                        data.mView.setLayoutParams(new ViewGroup.LayoutParams(
+                                ViewGroup.LayoutParams.FILL_PARENT,
+                                ViewGroup.LayoutParams.FILL_PARENT));
                         mFullScreenHolder.setContentView(data.mView);
                         mFullScreenHolder.setCancelable(false);
                         mFullScreenHolder.setCanceledOnTouchOutside(false);
                         mFullScreenHolder.show();
+                    } else if (mFullScreenHolder == null) {
+                        // this may happen if user dismisses the fullscreen and
+                        // then the WebCore re-position message finally reached
+                        // the UI thread.
+                        break;
                     }
                     // move the matching embedded view fully into the view so
                     // that touch will be valid instead of rejected due to out
@@ -6602,7 +6618,7 @@
     private native void     nativeDestroyLayer(int layer);
     private native int      nativeEvaluateLayersAnimations(int layer);
     private native boolean  nativeLayersHaveAnimations(int layer);
-    private native void     nativeUpdateLayers(int layer, int updates);
+    private native void     nativeUpdateLayers(int updates);
     private native void     nativeDrawLayers(int layer,
                                              int scrollX, int scrollY,
                                              int width, int height,
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index a09f23c..aa14c81 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -146,6 +146,19 @@
         }
     }
     
+    /**
+     * Utility to retrieve a view displaying a single permission.
+     */
+    public static View getPermissionItemView(Context context,
+            CharSequence grpName, CharSequence description, boolean dangerous) {
+        LayoutInflater inflater = (LayoutInflater)context.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        Drawable icon = context.getResources().getDrawable(dangerous
+                ? R.drawable.ic_bullet_key_permission : R.drawable.ic_text_dot);
+        return getPermissionItemView(context, inflater, grpName,
+                description, dangerous, icon);
+    }
+    
     private void getAllUsedPermissions(int sharedUid, Set<PermissionInfo> permSet) {
         String sharedPkgList[] = mPm.getPackagesForUid(sharedUid);
         if(sharedPkgList == null || (sharedPkgList.length == 0)) {
@@ -304,15 +317,20 @@
         mNoPermsView.setVisibility(View.VISIBLE);
     }
 
-    private View getPermissionItemView(CharSequence grpName, String permList,
+    private View getPermissionItemView(CharSequence grpName, CharSequence permList,
             boolean dangerous) {
-        View permView = mInflater.inflate(R.layout.app_permission_item, null);
-        Drawable icon = dangerous ? mDangerousIcon : mNormalIcon;
+        return getPermissionItemView(mContext, mInflater, grpName, permList,
+                dangerous, dangerous ? mDangerousIcon : mNormalIcon);
+    }
+
+    private static View getPermissionItemView(Context context, LayoutInflater inflater,
+            CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) {
+        View permView = inflater.inflate(R.layout.app_permission_item, null);
 
         TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
         TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
         if (dangerous) {
-            final Resources resources = mContext.getResources();
+            final Resources resources = context.getResources();
             permGrpView.setTextColor(resources.getColor(R.color.perms_dangerous_grp_color));
             permDescView.setTextColor(resources.getColor(R.color.perms_dangerous_perm_color));
         }
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 65f6845..9965fe5 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -645,6 +645,23 @@
     return chunkObject;
 }
 
+static void nativeSetDefaultConfig(JNIEnv* env, jobject, int nativeConfig) {
+    SkBitmap::Config config = static_cast<SkBitmap::Config>(nativeConfig);
+
+    // these are the only default configs that make sense for codecs right now
+    static const SkBitmap::Config gValidDefConfig[] = {
+        SkBitmap::kRGB_565_Config,
+        SkBitmap::kARGB_8888_Config,
+    };
+
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gValidDefConfig); i++) {
+        if (config == gValidDefConfig[i]) {
+            SkImageDecoder::SetDeviceConfig(config);
+            break;
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gMethods[] = {
@@ -671,8 +688,9 @@
     {   "nativeScaleNinePatch",
         "([BFLandroid/graphics/Rect;)[B",
         (void*)nativeScaleNinePatch
-    }
+    },
 
+    {   "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig },
 };
 
 static JNINativeMethod gOptionsMethods[] = {
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c6ef3a0..7728c50 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -938,6 +938,7 @@
             is a period then it is appended to your package name. -->
         <attr name="name" />
         <attr name="label" />
+        <attr name="description" />
         <attr name="icon" />
         <attr name="process" />
         <attr name="authorities" />
@@ -1016,6 +1017,7 @@
             is a period then it is appended to your package name. -->
         <attr name="name" />
         <attr name="label" />
+        <attr name="description" />
         <attr name="icon" />
         <attr name="permission" />
         <attr name="process" />
@@ -1047,6 +1049,7 @@
             is a period then it is appended to your package name. -->
         <attr name="name" />
         <attr name="label" />
+        <attr name="description" />
         <attr name="icon" />
         <attr name="permission" />
         <attr name="process" />
@@ -1078,6 +1081,7 @@
         <attr name="name" />
         <attr name="theme" />
         <attr name="label" />
+        <attr name="description" />
         <attr name="icon" />
         <attr name="launchMode" />
         <attr name="screenOrientation" />
@@ -1130,6 +1134,7 @@
              "com.mycompany.MyName". -->  
         <attr name="targetActivity" format="string" />
         <attr name="label" />
+        <attr name="description" />
         <attr name="icon" />
         <attr name="permission" />
         <!-- Specify whether the activity-alias is enabled or not (that is, can be instantiated by the system).
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 265dacd..0ef07ff 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1157,6 +1157,40 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_cache_filesystem">Allows an application to read and write the cache filesystem.</string>
 
+    <!-- Policy administration -->
+
+    <!-- Title of policy access to limiting the user's password choices -->
+    <string name="policylab_limitPassword">Limit password</string>
+    <!-- Description of policy access to limiting the user's password choices -->
+    <string name="policydesc_limitPassword">Restrict the types of passwords you
+        are allowed to use.</string>
+    <!-- Title of policy access to watch user login attempts -->
+    <string name="policylab_watchLogin">Watch login attempts</string>
+    <!-- Description of policy access to watch user login attempts -->
+    <string name="policydesc_watchLogin">Monitor attempts to login to
+        the device, in particular to respond to failed login attempts.</string>
+    <!-- Title of policy access to reset user's password -->
+    <string name="policylab_resetPassword">Reset your password</string>
+    <!-- Description of policy access to reset user's password -->
+    <string name="policydesc_resetPassword">Force your password
+        to a new value, requiring the administrator give it to you
+        before you can log in.</string>
+    <!-- Title of policy access to limiting the user's unlock timeout -->
+    <string name="policylab_limitUnlock">Limit lock timeout</string>
+    <!-- Description of policy access to limiting the user's unlock timeout -->
+    <string name="policydesc_limitUnlock">Restrict the unlock timeout
+        durations you can select.</string>
+    <!-- Title of policy access to force lock the device -->
+    <string name="policylab_forceLock">Force lock</string>
+    <!-- Description of policy access to limiting the user's password choices -->
+    <string name="policydesc_forceLock">Force the device to immediately lock,
+        requiring that its password is re-entered.</string>
+    <!-- Title of policy access to wipe the user's data -->
+    <string name="policylab_wipeData">Erase all data</string>
+    <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData">Perform a factory reset, deleting
+        all of your data without any confirmation from you.</string>
+
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
     <string-array name="phoneTypes">
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 3c03eed..2313f4c 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -558,6 +558,30 @@
         return decodeFileDescriptor(fd, null, null);
     }
 
+    /**
+     * Set the default config used for decoding bitmaps. This config is
+     * presented to the codec if the caller did not specify a preferred config
+     * in their call to decode...
+     *
+     * The default value is chosen by the system to best match the device's
+     * screen and memory constraints.
+     *
+     * @param config The preferred config for decoding bitmaps. If null, then
+     *               a suitable default is chosen by the system.
+     *
+     * @hide - only called by the browser at the moment, but should be stable
+     *   enough to expose if needed
+     */
+    public static void setDefaultConfig(Bitmap.Config config) {
+        if (config == null) {
+            // pick this for now, as historically it was our default.
+            // However, if we have a smarter algorithm, we can change this.
+            config = Bitmap.Config.RGB_565;
+        }
+        nativeSetDefaultConfig(config.nativeInt);
+    }
+
+    private static native void nativeSetDefaultConfig(int nativeConfig);
     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
             Rect padding, Options opts);
     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index 6ee9869..372909a 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -20,23 +20,23 @@
 
 #include <stdio.h>
 
-#include <utils/RefBase.h>
+#include <media/stagefright/MediaWriter.h>
 #include <utils/threads.h>
 
 namespace android {
 
 struct MediaSource;
 
-struct AMRWriter : public RefBase {
+struct AMRWriter : public MediaWriter {
     AMRWriter(const char *filename);
     AMRWriter(int fd);
 
     status_t initCheck() const;
 
-    status_t addSource(const sp<MediaSource> &source);
-
-    status_t start();
-    void stop();
+    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual bool reachedEOS();
+    virtual status_t start();
+    virtual void stop();
 
 protected:
     virtual ~AMRWriter();
@@ -49,6 +49,7 @@
     sp<MediaSource> mSource;
     bool mStarted;
     volatile bool mDone;
+    bool mReachedEOS;
     pthread_t mThread;
 
     static void *ThreadWrapper(void *);
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 2ca04fa..6b93f19 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -20,8 +20,8 @@
 
 #include <stdio.h>
 
+#include <media/stagefright/MediaWriter.h>
 #include <utils/List.h>
-#include <utils/RefBase.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -30,15 +30,15 @@
 class MediaSource;
 class MetaData;
 
-class MPEG4Writer : public RefBase {
+class MPEG4Writer : public MediaWriter {
 public:
     MPEG4Writer(const char *filename);
     MPEG4Writer(int fd);
 
-    void addSource(const sp<MediaSource> &source);
-    status_t start();
-    bool reachedEOS();
-    void stop();
+    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t start();
+    virtual bool reachedEOS();
+    virtual void stop();
 
     void beginBox(const char *fourcc);
     void writeInt8(int8_t x);
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
new file mode 100644
index 0000000..b8232c6
--- /dev/null
+++ b/include/media/stagefright/MediaWriter.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef MEDIA_WRITER_H_
+
+#define MEDIA_WRITER_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaSource;
+
+struct MediaWriter : public RefBase {
+    MediaWriter() {}
+
+    virtual status_t addSource(const sp<MediaSource> &source) = 0;
+    virtual bool reachedEOS() = 0;
+    virtual status_t start() = 0;
+    virtual void stop() = 0;
+
+protected:
+    virtual ~MediaWriter() {}
+
+private:
+    MediaWriter(const MediaWriter &);
+    MediaWriter &operator=(const MediaWriter &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_WRITER_H_
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
index 3c6da68..07f8933 100644
--- a/libs/rs/rsUtils.h
+++ b/libs/rs/rsUtils.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_RS_UTILS_H
 #define ANDROID_RS_UTILS_H
 
+#define LOG_NDEBUG 0
 #define LOG_TAG "RenderScript"
 #include <utils/Log.h>
 #include <utils/Vector.h>
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 4aac455..c4d4f99 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -489,7 +489,6 @@
 {
     int version;
     int fd;
-    int attempt;
     struct pollfd *new_mFDs;
     device_t **new_devices;
     char **new_device_names;
@@ -502,16 +501,11 @@
 
     AutoMutex _l(mLock);
 
-    for (attempt = 0; attempt < 10; attempt++) {
-        fd = open(deviceName, O_RDWR);
-        if (fd >= 0) break;
-        usleep(100);
-    }
+    fd = open(deviceName, O_RDWR);
     if(fd < 0) {
         LOGE("could not open %s, %s\n", deviceName, strerror(errno));
         return -1;
     }
-    LOGV("Opened device: %s (%d failures)", deviceName, attempt);
 
     if(ioctl(fd, EVIOCGVERSION, &version)) {
         LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index a55273d..6383f0c 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -20,6 +20,8 @@
 
 #include "StagefrightRecorder.h"
 
+#include <media/stagefright/AudioSource.h>
+#include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaDebug.h>
@@ -146,7 +148,90 @@
         return UNKNOWN_ERROR;
     }
 
-    if (mVideoSource == VIDEO_SOURCE_CAMERA) {
+    switch (mOutputFormat) {
+        case OUTPUT_FORMAT_DEFAULT:
+        case OUTPUT_FORMAT_THREE_GPP:
+        case OUTPUT_FORMAT_MPEG_4:
+            return startMPEG4Recording();
+
+        case OUTPUT_FORMAT_AMR_NB:
+        case OUTPUT_FORMAT_AMR_WB:
+            return startAMRRecording();
+
+        default:
+            return UNKNOWN_ERROR;
+    }
+}
+
+sp<MediaSource> StagefrightRecorder::createAMRAudioSource() {
+    uint32_t sampleRate =
+        mAudioEncoder == AUDIO_ENCODER_AMR_NB ? 8000 : 16000;
+
+    sp<AudioSource> audioSource =
+        new AudioSource(
+                mAudioSource,
+                sampleRate,
+                AudioSystem::CHANNEL_IN_MONO);
+
+    status_t err = audioSource->initCheck();
+
+    if (err != OK) {
+        return NULL;
+    }
+
+    sp<MetaData> encMeta = new MetaData;
+    encMeta->setCString(
+            kKeyMIMEType,
+            mAudioEncoder == AUDIO_ENCODER_AMR_NB
+                ? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB);
+
+    encMeta->setInt32(kKeyChannelCount, 1);
+    encMeta->setInt32(kKeySampleRate, sampleRate);
+
+    OMXClient client;
+    CHECK_EQ(client.connect(), OK);
+
+    sp<MediaSource> audioEncoder =
+        OMXCodec::Create(client.interface(), encMeta,
+                         true /* createEncoder */, audioSource);
+
+    return audioEncoder;
+}
+
+status_t StagefrightRecorder::startAMRRecording() {
+    if (mAudioSource == AUDIO_SOURCE_LIST_END
+        || mVideoSource != VIDEO_SOURCE_LIST_END) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (mOutputFormat == OUTPUT_FORMAT_AMR_NB
+            && mAudioEncoder != AUDIO_ENCODER_DEFAULT
+            && mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
+        return UNKNOWN_ERROR;
+    } else if (mOutputFormat == OUTPUT_FORMAT_AMR_WB
+            && mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MediaSource> audioEncoder = createAMRAudioSource();
+
+    if (audioEncoder == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    CHECK(mOutputFd >= 0);
+    mWriter = new AMRWriter(dup(mOutputFd));
+    mWriter->addSource(audioEncoder);
+    mWriter->start();
+
+    return OK;
+}
+
+status_t StagefrightRecorder::startMPEG4Recording() {
+    mWriter = new MPEG4Writer(dup(mOutputFd));
+
+    if (mVideoSource == VIDEO_SOURCE_DEFAULT
+            || mVideoSource == VIDEO_SOURCE_CAMERA) {
         CHECK(mCamera != NULL);
 
         sp<CameraSource> cameraSource =
@@ -193,11 +278,20 @@
                     true /* createEncoder */, cameraSource);
 
         CHECK(mOutputFd >= 0);
-        mWriter = new MPEG4Writer(dup(mOutputFd));
         mWriter->addSource(encoder);
-        mWriter->start();
     }
 
+    if (mAudioSource != AUDIO_SOURCE_LIST_END) {
+        sp<MediaSource> audioEncoder = createAMRAudioSource();
+
+        if (audioEncoder == NULL) {
+            return UNKNOWN_ERROR;
+        }
+
+        mWriter->addSource(audioEncoder);
+    }
+
+    mWriter->start();
     return OK;
 }
 
@@ -235,7 +329,9 @@
 }
 
 status_t StagefrightRecorder::getMaxAmplitude(int *max) {
-    return UNKNOWN_ERROR;
+    *max = 0;
+
+    return OK;
 }
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 56c4e0e..7ec412d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -23,7 +23,8 @@
 
 namespace android {
 
-class MPEG4Writer;
+struct MediaSource;
+struct MediaWriter;
 
 struct StagefrightRecorder : public MediaRecorderBase {
     StagefrightRecorder();
@@ -54,7 +55,7 @@
     sp<ICamera> mCamera;
     sp<ISurface> mPreviewSurface;
     sp<IMediaPlayerClient> mListener;
-    sp<MPEG4Writer> mWriter;
+    sp<MediaWriter> mWriter;
 
     audio_source mAudioSource;
     video_source mVideoSource;
@@ -66,6 +67,10 @@
     String8 mParams;
     int mOutputFd;
 
+    status_t startMPEG4Recording();
+    status_t startAMRRecording();
+    sp<MediaSource> createAMRAudioSource();
+
     StagefrightRecorder(const StagefrightRecorder &);
     StagefrightRecorder &operator=(const StagefrightRecorder &);
 };
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 7b681f12..caff452 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -115,6 +115,7 @@
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
+    mReachedEOS = false;
     mDone = false;
 
     pthread_create(&mThread, &attr, ThreadWrapper, this);
@@ -179,6 +180,14 @@
             break;
         }
     }
+
+    Mutex::Autolock autoLock(mLock);
+    mReachedEOS = true;
+}
+
+bool AMRWriter::reachedEOS() {
+    Mutex::Autolock autoLock(mLock);
+    return mReachedEOS;
 }
 
 }  // namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 367459f..aee4d15 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -92,9 +92,11 @@
     mTracks.clear();
 }
 
-void MPEG4Writer::addSource(const sp<MediaSource> &source) {
+status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
     Track *track = new Track(this, source);
     mTracks.push_back(track);
+
+    return OK;
 }
 
 status_t MPEG4Writer::start() {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2e45512..72e26f8 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -161,7 +161,7 @@
             = new HashMap<String,IBackupTransport>();
     String mCurrentTransport;
     IBackupTransport mLocalTransport, mGoogleTransport;
-    RestoreSession mActiveRestoreSession;
+    ActiveRestoreSession mActiveRestoreSession;
 
     class RestoreParams {
         public IBackupTransport transport;
@@ -2068,20 +2068,20 @@
                 Log.d(TAG, "Restore session requested but one already active");
                 return null;
             }
-            mActiveRestoreSession = new RestoreSession(transport);
+            mActiveRestoreSession = new ActiveRestoreSession(transport);
         }
         return mActiveRestoreSession;
     }
 
     // ----- Restore session -----
 
-    class RestoreSession extends IRestoreSession.Stub {
+    class ActiveRestoreSession extends IRestoreSession.Stub {
         private static final String TAG = "RestoreSession";
 
         private IBackupTransport mRestoreTransport = null;
         RestoreSet[] mRestoreSets = null;
 
-        RestoreSession(String transport) {
+        ActiveRestoreSession(String transport) {
             mRestoreTransport = getTransport(transport);
         }
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 5a8d35f..4417d7b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -828,6 +828,28 @@
                     info.getExtraInfo());
         }
 
+        NetworkStateTracker newNet = tryFailover(prevNetType);
+        if (newNet != null) {
+            NetworkInfo switchTo = newNet.getNetworkInfo();
+            intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
+        } else {
+            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+        }
+        // do this before we broadcast the change
+        handleConnectivityChange();
+
+        sendStickyBroadcast(intent);
+        /*
+         * If the failover network is already connected, then immediately send
+         * out a followup broadcast indicating successful failover
+         */
+        if (newNet != null && newNet.getNetworkInfo().isConnected()) {
+            sendConnectedBroadcast(newNet.getNetworkInfo());
+        }
+    }
+
+    // returns -1 if no failover available
+    private NetworkStateTracker tryFailover(int prevNetType) {
         /*
          * If this is a default network, check if other defaults are available
          * or active
@@ -840,8 +862,7 @@
 
             int newType = -1;
             int newPriority = -1;
-            for (int checkType=0; checkType <=
-                    ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
+            for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
                 if (checkType == prevNetType) continue;
                 if (mNetAttributes[checkType] == null) continue;
                 if (mNetAttributes[checkType].isDefault()) {
@@ -884,29 +905,13 @@
                                     switchTo.getTypeName());
                         }
                     }
-                    intent.putExtra(ConnectivityManager.
-                            EXTRA_OTHER_NETWORK_INFO, switchTo);
                 } else {
-                    intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
-                            true);
                     newNet.reconnect();
                 }
-            } else {
-                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
-                        true);
             }
         }
 
-        // do this before we broadcast the change
-        handleConnectivityChange();
-
-        sendStickyBroadcast(intent);
-        /*
-         * If the failover network is already connected, then immediately send
-         * out a followup broadcast indicating successful failover
-         */
-        if (newNet != null && newNet.getNetworkInfo().isConnected())
-            sendConnectedBroadcast(newNet.getNetworkInfo());
+        return newNet;
     }
 
     private void sendConnectedBroadcast(NetworkInfo info) {
@@ -964,7 +969,25 @@
             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
             info.setFailover(false);
         }
+
+        NetworkStateTracker newNet = tryFailover(info.getType());
+        if (newNet != null) {
+            NetworkInfo switchTo = newNet.getNetworkInfo();
+            intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
+        } else {
+            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+        }
+        // do this before we broadcast the change
+        handleConnectivityChange();
+
         sendStickyBroadcast(intent);
+        /*
+         * If the failover network is already connected, then immediately send
+         * out a followup broadcast indicating successful failover
+         */
+        if (newNet != null && newNet.getNetworkInfo().isConnected()) {
+            sendConnectedBroadcast(newNet.getNetworkInfo());
+        }
     }
 
     private void sendStickyBroadcast(Intent intent) {
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 36da4eb..fbd5317 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -91,7 +91,8 @@
         return mIPowerManager;
     }
     
-    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException {
+    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
+            throws SecurityException {
         if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingUid()) {
             if (who != null) {
                 if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName)
@@ -99,20 +100,27 @@
                     throw new SecurityException("Current admin is not " + who);
                 }
             }
+            if (!mActiveAdmin.info.usesPolicy(reqPolicy)) {
+                throw new SecurityException("Admin " + mActiveAdmin.info.getComponent()
+                        + " did not specify uses-policy for: "
+                        + mActiveAdmin.info.getTagForPolicy(reqPolicy));
+            }
             return mActiveAdmin;
         }
         throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid());
     }
     
-    
-    void sendAdminCommandLocked(ActiveAdmin policy, String action) {
+    void sendAdminCommandLocked(ActiveAdmin admin, String action) {
         Intent intent = new Intent(action);
-        intent.setComponent(policy.info.getComponent());
+        intent.setComponent(admin.info.getComponent());
         mContext.sendBroadcast(intent);
     }
     
-    void sendAdminCommandLocked(String action) {
+    void sendAdminCommandLocked(String action, int reqPolicy) {
         if (mActiveAdmin != null) {
+            if (mActiveAdmin.info.usesPolicy(reqPolicy)) {
+                return;
+            }
             sendAdminCommandLocked(mActiveAdmin, action);
         }
     }
@@ -353,7 +361,8 @@
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordMode != mode) {
                 ap.passwordMode = mode;
                 saveSettingsLocked();
@@ -373,7 +382,8 @@
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLength != length) {
                 ap.minimumPasswordLength = length;
                 saveSettingsLocked();
@@ -391,7 +401,8 @@
         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);
+            getActiveAdminForCallerLocked(null,
+                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             return mActivePasswordMode >= getPasswordMode()
                     && mActivePasswordLength >= getMinimumPasswordLength();
         }
@@ -401,7 +412,8 @@
         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);
+            getActiveAdminForCallerLocked(null,
+                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
             return mFailedPasswordAttempts;
         }
     }
@@ -411,7 +423,8 @@
         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);
+            getActiveAdminForCallerLocked(null,
+                    DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
             mode = getPasswordMode();
             if (password.length() < getMinimumPasswordLength()) {
                 return false;
@@ -436,7 +449,8 @@
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_LIMIT_UNLOCK);
             if (ap.maximumTimeToUnlock != timeMs) {
                 ap.maximumTimeToUnlock = timeMs;
                 
@@ -468,7 +482,8 @@
         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);
+            getActiveAdminForCallerLocked(null,
+                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
             // STOPSHIP need to implement.
         }
     }
@@ -477,7 +492,8 @@
         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);
+            getActiveAdminForCallerLocked(null,
+                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
         }
         long ident = Binder.clearCallingIdentity();
         try {
@@ -501,7 +517,8 @@
                     mActivePasswordMode = mode;
                     mActivePasswordLength = length;
                     mFailedPasswordAttempts = 0;
-                    sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED);
+                    sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED,
+                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -517,7 +534,8 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 mFailedPasswordAttempts++;
-                sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED);
+                sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED,
+                        DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -533,7 +551,8 @@
                 long ident = Binder.clearCallingIdentity();
                 try {
                     mFailedPasswordAttempts = 0;
-                    sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED);
+                    sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED,
+                            DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index cafc804..1307972 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2855,9 +2855,8 @@
     // room left on the data partition, or a ZipException if the package
     // file is malformed.
     //
-    private int cachePackageSharedLibsForAbiLI( PackageParser.Package  pkg,
-        File dataPath, File scanFile, String cpuAbi)
-    throws IOException, ZipException {
+    private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg,
+        File dataPath, File scanFile, String cpuAbi) throws IOException, ZipException {
         File sharedLibraryDir = new File(dataPath.getPath() + "/lib");
         final String apkLib = "lib/";
         final int apkLibLen = apkLib.length();
@@ -2935,7 +2934,7 @@
                 if (mInstaller == null) {
                     sharedLibraryDir.mkdir();
                 }
-                cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir,
+                cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
                         sharedLibraryFile);
             }
         }
@@ -2948,6 +2947,54 @@
         return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
     }
 
+    // Find the gdbserver executable program in a package at
+    // lib/<cpuAbi>/gdbserver and copy it to /data/data/<name>/lib/gdbserver
+    //
+    // Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success,
+    // or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise.
+    //
+    private int cachePackageGdbServerLI(PackageParser.Package pkg,
+        File dataPath, File scanFile, String cpuAbi) throws IOException, ZipException {
+        File installGdbServerDir = new File(dataPath.getPath() + "/lib");
+        final String GDBSERVER = "gdbserver";
+        final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER;
+
+        ZipFile zipFile = new ZipFile(scanFile);
+        Enumeration<ZipEntry> entries =
+            (Enumeration<ZipEntry>) zipFile.entries();
+
+        while (entries.hasMoreElements()) {
+            ZipEntry entry = entries.nextElement();
+            // skip directories
+            if (entry.isDirectory()) {
+                continue;
+            }
+            String entryName = entry.getName();
+
+            if (!entryName.equals(apkGdbServerPath)) {
+                continue;
+            }
+
+            String installGdbServerPath = installGdbServerDir.getPath() +
+                "/" + GDBSERVER;
+            File installGdbServerFile = new File(installGdbServerPath);
+            if (! installGdbServerFile.exists() ||
+                installGdbServerFile.length() != entry.getSize() ||
+                installGdbServerFile.lastModified() != entry.getTime()) {
+                if (Config.LOGD) {
+                    Log.d(TAG, "Caching gdbserver " + entry.getName());
+                }
+                if (mInstaller == null) {
+                    installGdbServerDir.mkdir();
+                }
+                cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
+                        installGdbServerFile);
+            }
+            return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
+        }
+        return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
+    }
+
     // extract shared libraries stored in the APK as lib/<cpuAbi>/lib<name>.so
     // and copy them to /data/data/<appname>/lib.
     //
@@ -2957,7 +3004,7 @@
     //
     private int cachePackageSharedLibsLI(PackageParser.Package  pkg,
         File dataPath, File scanFile) {
-        final String cpuAbi = Build.CPU_ABI;
+        String cpuAbi = Build.CPU_ABI;
         try {
             int result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi);
 
@@ -2968,7 +3015,7 @@
             //
             // only scan the package twice in case of ABI mismatch
             if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
-                String  cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
+                final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
                 if (cpuAbi2 != null) {
                     result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi2);
                 }
@@ -2977,6 +3024,20 @@
                     Log.w(TAG,"Native ABI mismatch from package file");
                     return PackageManager.INSTALL_FAILED_INVALID_APK;
                 }
+
+                if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
+                    cpuAbi = cpuAbi2;
+                }
+            }
+
+            // for debuggable packages, also extract gdbserver from lib/<abi>
+            // into /data/data/<appname>/lib too.
+            if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES &&
+                (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+                int result2 = cachePackageGdbServerLI(pkg, dataPath, scanFile, cpuAbi);
+                if (result2 == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
+                    pkg.applicationInfo.flags |= ApplicationInfo.FLAG_NATIVE_DEBUGGABLE;
+                }
             }
         } catch (ZipException e) {
             Log.w(TAG, "Failed to extract data from package file", e);
@@ -2988,26 +3049,27 @@
         return PackageManager.INSTALL_SUCCEEDED;
     }
 
-    private void cacheSharedLibLI(PackageParser.Package pkg,
+    private void cacheNativeBinaryLI(PackageParser.Package pkg,
             ZipFile zipFile, ZipEntry entry,
-            File sharedLibraryDir,
-            File sharedLibraryFile) throws IOException {
+            File binaryDir,
+            File binaryFile) throws IOException {
         InputStream inputStream = zipFile.getInputStream(entry);
         try {
-            File tempFile = File.createTempFile("tmp", "tmp", sharedLibraryDir);
+            File tempFile = File.createTempFile("tmp", "tmp", binaryDir);
             String tempFilePath = tempFile.getPath();
-            // XXX package manager can't change owner, so the lib files for
+            // XXX package manager can't change owner, so the executable files for
             // now need to be left as world readable and owned by the system.
             if (! FileUtils.copyToFile(inputStream, tempFile) ||
                 ! tempFile.setLastModified(entry.getTime()) ||
                 FileUtils.setPermissions(tempFilePath,
                         FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
+                        |FileUtils.S_IXUSR|FileUtils.S_IXGRP|FileUtils.S_IXOTH
                         |FileUtils.S_IROTH, -1, -1) != 0 ||
-                ! tempFile.renameTo(sharedLibraryFile)) {
+                ! tempFile.renameTo(binaryFile)) {
                 // Failed to properly write file.
                 tempFile.delete();
-                throw new IOException("Couldn't create cached shared lib "
-                        + sharedLibraryFile + " in " + sharedLibraryDir);
+                throw new IOException("Couldn't create cached binary "
+                        + binaryFile + " in " + binaryDir);
             }
         } finally {
             inputStream.close();