Merge "remove dependency on android_native{s_priv|buffer}.h"
diff --git a/api/current.txt b/api/current.txt
index e0dad49..fffa1fe 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6195,6 +6195,8 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int REQUESTED_PERMISSION_GRANTED = 2; // 0x2
+    field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
     field public android.content.pm.ActivityInfo[] activities;
     field public android.content.pm.ApplicationInfo applicationInfo;
     field public android.content.pm.ConfigurationInfo[] configPreferences;
@@ -6208,6 +6210,7 @@
     field public android.content.pm.ActivityInfo[] receivers;
     field public android.content.pm.FeatureInfo[] reqFeatures;
     field public java.lang.String[] requestedPermissions;
+    field public int[] requestedPermissionsFlags;
     field public android.content.pm.ServiceInfo[] services;
     field public java.lang.String sharedUserId;
     field public int sharedUserLabel;
@@ -6430,6 +6433,10 @@
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int PROTECTION_DANGEROUS = 1; // 0x1
+    field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20
+    field public static final int PROTECTION_FLAG_SYSTEM = 16; // 0x10
+    field public static final int PROTECTION_MASK_BASE = 15; // 0xf
+    field public static final int PROTECTION_MASK_FLAGS = 240; // 0xf0
     field public static final int PROTECTION_NORMAL = 0; // 0x0
     field public static final int PROTECTION_SIGNATURE = 2; // 0x2
     field public static final int PROTECTION_SIGNATURE_OR_SYSTEM = 3; // 0x3
@@ -21935,12 +21942,14 @@
     method public java.lang.Object getTag();
     method public abstract java.lang.CharSequence getTitle();
     method public abstract void invalidate();
+    method public boolean isTitleOptional();
     method public abstract void setCustomView(android.view.View);
     method public abstract void setSubtitle(java.lang.CharSequence);
     method public abstract void setSubtitle(int);
     method public void setTag(java.lang.Object);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitle(int);
+    method public void setTitleOptionalHint(boolean);
   }
 
   public static abstract interface ActionMode.Callback {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index f457842..ac5bffe 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -126,6 +126,16 @@
             return;
         }
 
+        if ("grant".equals(op)) {
+            runGrantRevokePermission(true);
+            return;
+        }
+
+        if ("revoke".equals(op)) {
+            runGrantRevokePermission(false);
+            return;
+        }
+
         if ("set-install-location".equals(op)) {
             runSetInstallLocation();
             return;
@@ -596,8 +606,9 @@
                 if (groups && groupName == null && pi.group != null) {
                     continue;
                 }
-                if (pi.protectionLevel < startProtectionLevel
-                        || pi.protectionLevel > endProtectionLevel) {
+                final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+                if (base < startProtectionLevel
+                        || base > endProtectionLevel) {
                     continue;
                 }
                 if (summary) {
@@ -627,22 +638,8 @@
                                     + loadText(pi, pi.descriptionRes,
                                             pi.nonLocalizedDescription));
                         }
-                        String protLevel = "unknown";
-                        switch(pi.protectionLevel) {
-                            case PermissionInfo.PROTECTION_DANGEROUS:
-                                protLevel = "dangerous";
-                                break;
-                            case PermissionInfo.PROTECTION_NORMAL:
-                                protLevel = "normal";
-                                break;
-                            case PermissionInfo.PROTECTION_SIGNATURE:
-                                protLevel = "signature";
-                                break;
-                            case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM:
-                                protLevel = "signatureOrSystem";
-                                break;
-                        }
-                        System.out.println(prefix + "  protectionLevel:" + protLevel);
+                        System.out.println(prefix + "  protectionLevel:"
+                                + PermissionInfo.protectionToString(pi.protectionLevel));
                     }
                 }
             }
@@ -1063,6 +1060,36 @@
         }
     }
 
+    private void runGrantRevokePermission(boolean grant) {
+        String pkg = nextArg();
+        if (pkg == null) {
+            System.err.println("Error: no package specified");
+            showUsage();
+            return;
+        }
+        String perm = nextArg();
+        if (perm == null) {
+            System.err.println("Error: no permission specified");
+            showUsage();
+            return;
+        }
+        try {
+            if (grant) {
+                mPm.grantPermission(pkg, perm);
+            } else {
+                mPm.revokePermission(pkg, perm);
+            }
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(PM_NOT_RUNNING_ERR);
+        } catch (IllegalArgumentException e) {
+            System.err.println("Bad argument: " + e.toString());
+            showUsage();
+        } catch (SecurityException e) {
+            System.err.println("Operation not allowed: " + e.toString());
+        }
+    }
+
     /**
      * Displays the package file for a package.
      * @param pckg
@@ -1158,6 +1185,8 @@
         System.err.println("       pm enable PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable-user PACKAGE_OR_COMPONENT");
+        System.err.println("       pm grant PACKAGE PERMISSION");
+        System.err.println("       pm revoke PACKAGE PERMISSION");
         System.err.println("       pm set-install-location [0/auto] [1/internal] [2/external]");
         System.err.println("       pm get-install-location");
         System.err.println("       pm create-profile USER_NAME");
@@ -1208,6 +1237,10 @@
         System.err.println("pm enable, disable, disable-user: these commands change the enabled state");
         System.err.println("  of a given package or component (written as \"package/class\").");
         System.err.println("");
+        System.err.println("pm grant, revoke: these commands either grant or revoke permissions");
+        System.err.println("  to applications.  Only optional permissions the application has");
+        System.err.println("  declared can be granted or revoked.");
+        System.err.println("");
         System.err.println("pm get-install-location: returns the current install location.");
         System.err.println("    0 [auto]: Let system decide the best location");
         System.err.println("    1 [internal]: Install on internal device storage");
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bf632a9..5d1d461 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -78,6 +78,7 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
+import android.renderscript.RenderScript;
 
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.RuntimeInit;
@@ -3779,6 +3780,7 @@
                 appContext.init(info, null, this);
 
                 HardwareRenderer.setupDiskCache(appContext.getCacheDir());
+                RenderScript.setupDiskCache(appContext.getCacheDir());
             }
         } catch (RemoteException e) {
             // Ignore
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index fee2beb..758ce09 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -332,6 +332,24 @@
     }
 
     @Override
+    public void grantPermission(String packageName, String permissionName) {
+        try {
+            mPM.grantPermission(packageName, permissionName);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Package manager has died", e);
+        }
+    }
+
+    @Override
+    public void revokePermission(String packageName, String permissionName) {
+        try {
+            mPM.revokePermission(packageName, permissionName);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Package manager has died", e);
+        }
+    }
+
+    @Override
     public int checkSignatures(String pkg1, String pkg2) {
         try {
             return mPM.checkSignatures(pkg1, pkg2);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index bb35c29..95b6fee 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -81,7 +81,11 @@
     boolean addPermission(in PermissionInfo info);
     
     void removePermission(String name);
-    
+
+    void grantPermission(String packageName, String permissionName);
+
+    void revokePermission(String packageName, String permissionName);
+
     boolean isProtectedBroadcast(String actionName);
     
     int checkSignatures(String pkg1, String pkg2);
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index eb05d76..415d58a 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -141,6 +141,30 @@
     public String[] requestedPermissions;
     
     /**
+     * Array of flags of all {@link android.R.styleable#AndroidManifestUsesPermission
+     * &lt;uses-permission&gt;} tags included under &lt;manifest&gt;,
+     * or null if there were none.  This is only filled in if the flag
+     * {@link PackageManager#GET_PERMISSIONS} was set.  Each value matches
+     * the corresponding entry in {@link #requestedPermissions}, and will have
+     * the flags {@link #REQUESTED_PERMISSION_REQUIRED} and
+     * {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
+     */
+    public int[] requestedPermissionsFlags;
+
+    /**
+     * Flag for {@link #requestedPermissionsFlags}: the requested permission
+     * is required for the application to run; the user can not optionally
+     * disable it.
+     */
+    public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
+
+    /**
+     * Flag for {@link #requestedPermissionsFlags}: the requested permission
+     * is currently granted to the application.
+     */
+    public static final int REQUESTED_PERMISSION_GRANTED = 1<<1;
+
+    /**
      * Array of all signatures read from the package file.  This is only filled
      * in if the flag {@link PackageManager#GET_SIGNATURES} was set.
      */
@@ -229,6 +253,7 @@
         dest.writeTypedArray(instrumentation, parcelableFlags);
         dest.writeTypedArray(permissions, parcelableFlags);
         dest.writeStringArray(requestedPermissions);
+        dest.writeIntArray(requestedPermissionsFlags);
         dest.writeTypedArray(signatures, parcelableFlags);
         dest.writeTypedArray(configPreferences, parcelableFlags);
         dest.writeTypedArray(reqFeatures, parcelableFlags);
@@ -266,6 +291,7 @@
         instrumentation = source.createTypedArray(InstrumentationInfo.CREATOR);
         permissions = source.createTypedArray(PermissionInfo.CREATOR);
         requestedPermissions = source.createStringArray();
+        requestedPermissionsFlags = source.createIntArray();
         signatures = source.createTypedArray(Signature.CREATOR);
         configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
         reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 26a9181..f2133d8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1475,6 +1475,29 @@
     public abstract void removePermission(String name);
 
     /**
+     * Grant a permission to an application which the application does not
+     * already have.  The permission must have been requested by the application,
+     * but as an optional permission.  If the application is not allowed to
+     * hold the permission, a SecurityException is thrown.
+     * @hide
+     *
+     * @param packageName The name of the package that the permission will be
+     * granted to.
+     * @param permissionName The name of the permission.
+     */
+    public abstract void grantPermission(String packageName, String permissionName);
+
+    /**
+     * Revoke a permission that was previously granted by {@link #grantPermission}.
+     * @hide
+     *
+     * @param packageName The name of the package that the permission will be
+     * granted to.
+     * @param permissionName The name of the permission.
+     */
+    public abstract void revokePermission(String packageName, String permissionName);
+
+    /**
      * Compare the signatures of two packages to determine if the same
      * signature appears in both of them.  If they do contain the same
      * signature, then they are allowed special privileges when working
@@ -2125,7 +2148,7 @@
         if ((flags & GET_SIGNATURES) != 0) {
             packageParser.collectCertificates(pkg, 0);
         }
-        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0);
+        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null);
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8029bd5..7b4a0ad 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -51,6 +51,7 @@
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.jar.Attributes;
@@ -211,7 +212,8 @@
      * @param flags indicating which optional information is included.
      */
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
-            int gids[], int flags, long firstInstallTime, long lastUpdateTime) {
+            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
+            HashSet<String> grantedPermissions) {
 
         final int userId = Binder.getOrigCallingUser();
 
@@ -346,8 +348,16 @@
             N = p.requestedPermissions.size();
             if (N > 0) {
                 pi.requestedPermissions = new String[N];
+                pi.requestedPermissionsFlags = new int[N];
                 for (int i=0; i<N; i++) {
-                    pi.requestedPermissions[i] = p.requestedPermissions.get(i);
+                    final String perm = p.requestedPermissions.get(i);
+                    pi.requestedPermissions[i] = perm;
+                    if (p.requestedPermissionsRequired.get(i)) {
+                        pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
+                    }
+                    if (grantedPermissions != null && grantedPermissions.contains(perm)) {
+                        pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
+                    }
                 }
             }
         }
@@ -927,11 +937,14 @@
                 // that may change.
                 String name = sa.getNonResourceString(
                         com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
+                boolean required = sa.getBoolean(
+                        com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
 
                 sa.recycle();
 
                 if (name != null && !pkg.requestedPermissions.contains(name)) {
                     pkg.requestedPermissions.add(name.intern());
+                    pkg.requestedPermissionsRequired.add(required);
                 }
 
                 XmlUtils.skipCurrentTag(parser);
@@ -1419,12 +1432,24 @@
                 PermissionInfo.PROTECTION_NORMAL);
 
         sa.recycle();
-        
+
         if (perm.info.protectionLevel == -1) {
             outError[0] = "<permission> does not specify protectionLevel";
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return null;
         }
+
+        perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
+
+        if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
+            if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
+                    PermissionInfo.PROTECTION_SIGNATURE) {
+                outError[0] = "<permission>  protectionLevel specifies a flag but is "
+                        + "not based on signature type";
+                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                return null;
+            }
+        }
         
         if (!parseAllMetaData(res, parser, attrs, "<permission>", perm,
                 outError)) {
@@ -2951,6 +2976,7 @@
         public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
 
         public final ArrayList<String> requestedPermissions = new ArrayList<String>();
+        public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
 
         public ArrayList<String> protectedBroadcasts;
         
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 3cc884b..69b812c 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -55,6 +55,30 @@
     public static final int PROTECTION_SIGNATURE_OR_SYSTEM = 3;
 
     /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>system</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     */
+    public static final int PROTECTION_FLAG_SYSTEM = 0x10;
+
+    /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>development</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     */
+    public static final int PROTECTION_FLAG_DEVELOPMENT = 0x20;
+
+    /**
+     * Mask for {@link #protectionLevel}: the basic protection type.
+     */
+    public static final int PROTECTION_MASK_BASE = 0xf;
+
+    /**
+     * Mask for {@link #protectionLevel}: additional flag bits.
+     */
+    public static final int PROTECTION_MASK_FLAGS = 0xf0;
+
+    /**
      * The group this permission is a part of, as per
      * {@link android.R.attr#permissionGroup}.
      */
@@ -79,10 +103,47 @@
      * The level of access this permission is protecting, as per
      * {@link android.R.attr#protectionLevel}.  Values may be
      * {@link #PROTECTION_NORMAL}, {@link #PROTECTION_DANGEROUS}, or
+     * {@link #PROTECTION_SIGNATURE}.  May also include the additional
+     * flags {@link #PROTECTION_FLAG_SYSTEM} or {@link #PROTECTION_FLAG_DEVELOPMENT}
+     * (which only make sense in combination with the base
      * {@link #PROTECTION_SIGNATURE}.
      */
     public int protectionLevel;
 
+    /** @hide */
+    public static int fixProtectionLevel(int level) {
+        if (level == PROTECTION_SIGNATURE_OR_SYSTEM) {
+            level = PROTECTION_SIGNATURE | PROTECTION_FLAG_SYSTEM;
+        }
+        return level;
+    }
+
+    /** @hide */
+    public static String protectionToString(int level) {
+        String protLevel = "????";
+        switch (level&PROTECTION_MASK_BASE) {
+            case PermissionInfo.PROTECTION_DANGEROUS:
+                protLevel = "dangerous";
+                break;
+            case PermissionInfo.PROTECTION_NORMAL:
+                protLevel = "normal";
+                break;
+            case PermissionInfo.PROTECTION_SIGNATURE:
+                protLevel = "signature";
+                break;
+            case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM:
+                protLevel = "signatureOrSystem";
+                break;
+        }
+        if ((level&PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {
+            protLevel += "|system";
+        }
+        if ((level&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+            protLevel += "|development";
+        }
+        return protLevel;
+    }
+
     public PermissionInfo() {
     }
 
diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java
index 220214b..5696839 100644
--- a/core/java/android/inputmethodservice/ExtractEditLayout.java
+++ b/core/java/android/inputmethodservice/ExtractEditLayout.java
@@ -124,6 +124,12 @@
         }
 
         @Override
+        public boolean isTitleOptional() {
+            // Not only is it optional, it will *never* be shown.
+            return true;
+        }
+
+        @Override
         public void setCustomView(View view) {
             // Custom view is not supported here.
         }
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index c1c7fe2..0ba5fdb 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -104,6 +104,32 @@
     public abstract void setSubtitle(int resId);
 
     /**
+     * Set whether or not the title/subtitle display for this action mode
+     * is optional.
+     *
+     * <p>In many cases the supplied title for an action mode is merely
+     * meant to add context and is not strictly required for the action
+     * mode to be useful. If the title is optional, the system may choose
+     * to hide the title entirely rather than truncate it due to a lack
+     * of available space.</p>
+     *
+     * <p>Note that this is merely a hint; the underlying implementation
+     * may choose to ignore this setting under some circumstances.</p>
+     *
+     * @param titleOptional true if the title only presents optional information.
+     */
+    public void setTitleOptionalHint(boolean titleOptional) {
+    }
+
+    /**
+     * @return true if this action mode considers the title and subtitle fields
+     *         as optional. Optional titles may not be displayed to the user.
+     */
+    public boolean isTitleOptional() {
+        return false;
+    }
+
+    /**
      * Set a custom view for this action mode. The custom view will take the place of
      * the title and subtitle. Useful for things like search boxes.
      *
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index f5fc708..36582af 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1208,14 +1208,38 @@
     @Override
     public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
             float vOffset, Paint paint) {
-        // TODO: Implement
+        if (index < 0 || index + count > text.length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        int modifiers = setupModifiers(paint);
+        try {
+            nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
+                    paint.mBidiFlags, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
+    private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
+            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
+
     @Override
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
-        // TODO: Implement
+        if (text.length() == 0) return;
+
+        int modifiers = setupModifiers(paint);
+        try {
+            nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
+                    paint.mBidiFlags, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
+    private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
+            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
+
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
             float x, float y, int dir, Paint paint) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index c51d244..b6b27c1 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -26,7 +26,6 @@
 import com.android.internal.view.InputBindResult;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -198,7 +197,31 @@
 
     static final Object mInstanceSync = new Object();
     static InputMethodManager mInstance;
-    
+
+    /**
+     * @hide Flag for IInputMethodManager.windowGainedFocus: a view in
+     * the window has input focus.
+     */
+    public static final int CONTROL_WINDOW_VIEW_HAS_FOCUS = 1<<0;
+
+    /**
+     * @hide Flag for IInputMethodManager.windowGainedFocus: the focus
+     * is a text editor.
+     */
+    public static final int CONTROL_WINDOW_IS_TEXT_EDITOR = 1<<1;
+
+    /**
+     * @hide Flag for IInputMethodManager.windowGainedFocus: this is the first
+     * time the window has gotten focus.
+     */
+    public static final int CONTROL_WINDOW_FIRST = 1<<2;
+
+    /**
+     * @hide Flag for IInputMethodManager.startInput: this is the first
+     * time the window has gotten focus.
+     */
+    public static final int CONTROL_START_INITIAL = 1<<8;
+
     final IInputMethodManager mService;
     final Looper mMainLooper;
     
@@ -216,7 +239,7 @@
     
     /**
      * Set whenever this client becomes inactive, to know we need to reset
-     * state with the IME then next time we receive focus.
+     * state with the IME the next time we receive focus.
      */
     boolean mHasBeenInactive = true;
     
@@ -243,11 +266,6 @@
      */
     View mNextServedView;
     /**
-     * True if we should restart input in the next served view, even if the
-     * view hasn't actually changed from the current serve view.
-     */
-    boolean mNextServedNeedsStart;
-    /**
      * This is set when we are in the process of connecting, to determine
      * when we have actually finished.
      */
@@ -331,7 +349,7 @@
                         mCurId = res.id;
                         mBindSequence = res.sequence;
                     }
-                    startInputInner();
+                    startInputInner(null, 0, 0, 0);
                     return;
                 }
                 case MSG_UNBIND: {
@@ -362,7 +380,7 @@
                         }
                     }
                     if (startInput) {
-                        startInputInner();
+                        startInputInner(null, 0, 0, 0);
                     }
                     return;
                 }
@@ -957,10 +975,11 @@
             mServedConnecting = true;
         }
         
-        startInputInner();
+        startInputInner(null, 0, 0, 0);
     }
     
-    void startInputInner() {
+    boolean startInputInner(IBinder windowGainingFocus, int controlFlags, int softInputMode,
+            int windowFlags) {
         final View view;
         synchronized (mH) {
             view = mServedView;
@@ -969,7 +988,7 @@
             if (DEBUG) Log.v(TAG, "Starting input: view=" + view);
             if (view == null) {
                 if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
-                return;
+                return false;
             }
         }
         
@@ -982,7 +1001,7 @@
             // If the view doesn't have a handler, something has changed out
             // from under us, so just bail.
             if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!");
-            return;
+            return false;
         }
         if (vh.getLooper() != Looper.myLooper()) {
             // The view is running on a different thread than our own, so
@@ -990,10 +1009,10 @@
             if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
             vh.post(new Runnable() {
                 public void run() {
-                    startInputInner();
+                    startInputInner(null, 0, 0, 0);
                 }
             });
-            return;
+            return false;
         }
         
         // Okay we are now ready to call into the served view and have it
@@ -1013,12 +1032,14 @@
                 if (DEBUG) Log.v(TAG, 
                         "Starting input: finished by someone else (view="
                         + mServedView + " conn=" + mServedConnecting + ")");
-                return;
+                return false;
             }
-            
+
             // If we already have a text box, then this view is already
             // connected so we want to restart it.
-            final boolean initial = mCurrentTextBoxAttribute == null;
+            if (mCurrentTextBoxAttribute == null) {
+                controlFlags |= CONTROL_START_INITIAL;
+            }
             
             // Hook 'em up and let 'er rip.
             mCurrentTextBoxAttribute = tba;
@@ -1040,9 +1061,17 @@
             
             try {
                 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
-                        + ic + " tba=" + tba + " initial=" + initial);
-                InputBindResult res = mService.startInput(mClient,
-                        servedContext, tba, initial, true);
+                        + ic + " tba=" + tba + " controlFlags=#"
+                        + Integer.toHexString(controlFlags));
+                InputBindResult res;
+                if (windowGainingFocus != null) {
+                    res = mService.windowGainedFocus(mClient, windowGainingFocus,
+                            controlFlags, softInputMode, windowFlags,
+                            tba, servedContext);
+                } else {
+                    res = mService.startInput(mClient,
+                            servedContext, tba, controlFlags);
+                }
                 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
                 if (res != null) {
                     if (res.id != null) {
@@ -1051,7 +1080,7 @@
                     } else if (mCurMethod == null) {
                         // This means there is no input method available.
                         if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
-                        return;
+                        return true;
                     }
                 }
                 if (mCurMethod != null && mCompletions != null) {
@@ -1064,6 +1093,8 @@
                 Log.w(TAG, "IME died: " + mCurId, e);
             }
         }
+
+        return true;
     }
 
     /**
@@ -1139,27 +1170,26 @@
      * @hide
      */
     public void checkFocus() {
-        if (checkFocusNoStartInput()) {
-            startInputInner();
+        if (checkFocusNoStartInput(false)) {
+            startInputInner(null, 0, 0, 0);
         }
     }
 
-    private boolean checkFocusNoStartInput() {
+    private boolean checkFocusNoStartInput(boolean forceNewFocus) {
         // This is called a lot, so short-circuit before locking.
-        if (mServedView == mNextServedView && !mNextServedNeedsStart) {
+        if (mServedView == mNextServedView && !forceNewFocus) {
             return false;
         }
 
         InputConnection ic = null;
         synchronized (mH) {
-            if (mServedView == mNextServedView && !mNextServedNeedsStart) {
+            if (mServedView == mNextServedView && !forceNewFocus) {
                 return false;
             }
             if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
                     + " next=" + mNextServedView
-                    + " restart=" + mNextServedNeedsStart);
+                    + " forceNewFocus=" + forceNewFocus);
 
-            mNextServedNeedsStart = false;
             if (mNextServedView == null) {
                 finishInputLocked();
                 // In this case, we used to have a focused view on the window,
@@ -1190,13 +1220,14 @@
         } catch (RemoteException e) {
         }
     }
-    
+
     /**
      * Called by ViewAncestor when its window gets input focus.
      * @hide
      */
     public void onWindowFocus(View rootView, View focusedView, int softInputMode,
             boolean first, int windowFlags) {
+        boolean forceNewFocus = false;
         synchronized (mH) {
             if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
                     + " softInputMode=" + softInputMode
@@ -1205,26 +1236,41 @@
             if (mHasBeenInactive) {
                 if (DEBUG) Log.v(TAG, "Has been inactive!  Starting fresh");
                 mHasBeenInactive = false;
-                mNextServedNeedsStart = true;
+                forceNewFocus = true;
             }
             focusInLocked(focusedView != null ? focusedView : rootView);
         }
-        
-        boolean startInput = checkFocusNoStartInput();
-        
-        synchronized (mH) {
-            try {
-                final boolean isTextEditor = focusedView != null &&
-                        focusedView.onCheckIsTextEditor();
-                mService.windowGainedFocus(mClient, rootView.getWindowToken(),
-                        focusedView != null, isTextEditor, softInputMode, first,
-                        windowFlags);
-            } catch (RemoteException e) {
+
+        int controlFlags = 0;
+        if (focusedView != null) {
+            controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS;
+            if (focusedView.onCheckIsTextEditor()) {
+                controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR;
             }
         }
-
-        if (startInput) {
-            startInputInner();
+        if (first) {
+            controlFlags |= CONTROL_WINDOW_FIRST;
+        }
+        
+        if (checkFocusNoStartInput(forceNewFocus)) {
+            // We need to restart input on the current focus view.  This
+            // should be done in conjunction with telling the system service
+            // about the window gaining focus, to help make the transition
+            // smooth.
+            if (startInputInner(rootView.getWindowToken(),
+                    controlFlags, softInputMode, windowFlags)) {
+                return;
+            }
+        }
+        
+        // For some reason we didn't do a startInput + windowFocusGain, so
+        // we'll just do a window focus gain and call it a day.
+        synchronized (mH) {
+            try {
+                mService.windowGainedFocus(mClient, rootView.getWindowToken(),
+                        controlFlags, softInputMode, windowFlags, null, null);
+            } catch (RemoteException e) {
+            }
         }
     }
     
@@ -1676,8 +1722,7 @@
         p.println("  mCurMethod=" + mCurMethod);
         p.println("  mCurRootView=" + mCurRootView);
         p.println("  mServedView=" + mServedView);
-        p.println("  mNextServedNeedsStart=" + mNextServedNeedsStart
-                + " mNextServedView=" + mNextServedView);
+        p.println("  mNextServedView=" + mNextServedView);
         p.println("  mServedConnecting=" + mServedConnecting);
         if (mCurrentTextBoxAttribute != null) {
             p.println("  mCurrentTextBoxAttribute:");
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index cdf20f6..2a770f5 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -53,10 +53,8 @@
         mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy, menu);
 
         final Context context = mWebView.getContext();
-        boolean allowText = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
-        mode.setTitle(allowText ?
-                context.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
+        mode.setTitle(context.getString(com.android.internal.R.string.textSelectionCABTitle));
+        mode.setTitleOptionalHint(true);
 
         // If the action mode UI we're running in isn't capable of taking window focus
         // the user won't be able to type into the find on page UI. Disable this functionality.
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 988760d..e6184d5 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -26,6 +26,12 @@
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.ForegroundColorSpan;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -61,18 +67,52 @@
         BOTH
     }
 
+    static class MyPermissionInfo extends PermissionInfo {
+        /**
+         * PackageInfo.requestedPermissionsFlags for the new package being installed.
+         */
+        int mNewReqFlags;
+
+        /**
+         * PackageInfo.requestedPermissionsFlags for the currently installed
+         * package, if it is installed.
+         */
+        int mExistingReqFlags;
+
+        /**
+         * True if this should be considered a new permission.
+         */
+        boolean mNew;
+
+        MyPermissionInfo() {
+        }
+
+        MyPermissionInfo(PermissionInfo info) {
+            super(info);
+        }
+
+        MyPermissionInfo(MyPermissionInfo info) {
+            super(info);
+            mNewReqFlags = info.mNewReqFlags;
+            mExistingReqFlags = info.mExistingReqFlags;
+            mNew = info.mNew;
+        }
+    }
+
     private final static String TAG = "AppSecurityPermissions";
     private boolean localLOGV = false;
     private Context mContext;
     private LayoutInflater mInflater;
     private PackageManager mPm;
     private LinearLayout mPermsView;
-    private Map<String, String> mDangerousMap;
-    private Map<String, String> mNormalMap;
-    private List<PermissionInfo> mPermsList;
+    private Map<String, CharSequence> mNewMap;
+    private Map<String, CharSequence> mDangerousMap;
+    private Map<String, CharSequence> mNormalMap;
+    private List<MyPermissionInfo> mPermsList;
     private String mDefaultGrpLabel;
     private String mDefaultGrpName="DefaultGrp";
     private String mPermFormat;
+    private CharSequence mNewPermPrefix;
     private Drawable mNormalIcon;
     private Drawable mDangerousIcon;
     private boolean mExpanded;
@@ -84,20 +124,23 @@
     private State mCurrentState;
     private LinearLayout mNonDangerousList;
     private LinearLayout mDangerousList;
+    private LinearLayout mNewList;
     private HashMap<String, CharSequence> mGroupLabelCache;
     private View mNoPermsView;
-    
+
     public AppSecurityPermissions(Context context, List<PermissionInfo> permList) {
         mContext = context;
         mPm = mContext.getPackageManager();
-        mPermsList = permList;
+        for (PermissionInfo pi : permList) {
+            mPermsList.add(new MyPermissionInfo(pi));
+        }
     }
     
     public AppSecurityPermissions(Context context, String packageName) {
         mContext = context;
         mPm = mContext.getPackageManager();
-        mPermsList = new ArrayList<PermissionInfo>();
-        Set<PermissionInfo> permSet = new HashSet<PermissionInfo>();
+        mPermsList = new ArrayList<MyPermissionInfo>();
+        Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>();
         PackageInfo pkgInfo;
         try {
             pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
@@ -109,7 +152,7 @@
         if((pkgInfo.applicationInfo != null) && (pkgInfo.applicationInfo.uid != -1)) {
             getAllUsedPermissions(pkgInfo.applicationInfo.uid, permSet);
         }
-        for(PermissionInfo tmpInfo : permSet) {
+        for(MyPermissionInfo tmpInfo : permSet) {
             mPermsList.add(tmpInfo);
         }
     }
@@ -117,21 +160,27 @@
     public AppSecurityPermissions(Context context, PackageParser.Package pkg) {
         mContext = context;
         mPm = mContext.getPackageManager();
-        mPermsList = new ArrayList<PermissionInfo>();
-        Set<PermissionInfo> permSet = new HashSet<PermissionInfo>();
+        mPermsList = new ArrayList<MyPermissionInfo>();
+        Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>();
         if(pkg == null) {
             return;
         }
+
+        // Convert to a PackageInfo
+        PackageInfo info = PackageParser.generatePackageInfo(pkg, null,
+                PackageManager.GET_PERMISSIONS, 0, 0, null);
+        PackageInfo installedPkgInfo = null;
         // Get requested permissions
-        if (pkg.requestedPermissions != null) {
-            ArrayList<String> strList = pkg.requestedPermissions;
-            int size = strList.size();
-            if (size > 0) {
-                extractPerms(strList.toArray(new String[size]), permSet);
+        if (info.requestedPermissions != null) {
+            try {
+                installedPkgInfo = mPm.getPackageInfo(info.packageName,
+                        PackageManager.GET_PERMISSIONS);
+            } catch (NameNotFoundException e) {
             }
+            extractPerms(info, permSet, installedPkgInfo);
         }
         // Get permissions related to  shared user if any
-        if(pkg.mSharedUserId != null) {
+        if (pkg.mSharedUserId != null) {
             int sharedUid;
             try {
                 sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId);
@@ -141,7 +190,7 @@
             }
         }
         // Retrieve list of permissions
-        for(PermissionInfo tmpInfo : permSet) {
+        for (MyPermissionInfo tmpInfo : permSet) {
             mPermsList.add(tmpInfo);
         }
     }
@@ -159,7 +208,7 @@
                 description, dangerous, icon);
     }
     
-    private void getAllUsedPermissions(int sharedUid, Set<PermissionInfo> permSet) {
+    private void getAllUsedPermissions(int sharedUid, Set<MyPermissionInfo> permSet) {
         String sharedPkgList[] = mPm.getPackagesForUid(sharedUid);
         if(sharedPkgList == null || (sharedPkgList.length == 0)) {
             return;
@@ -170,29 +219,65 @@
     }
     
     private void getPermissionsForPackage(String packageName, 
-            Set<PermissionInfo> permSet) {
+            Set<MyPermissionInfo> permSet) {
         PackageInfo pkgInfo;
         try {
             pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
         } catch (NameNotFoundException e) {
-            Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName);
+            Log.w(TAG, "Couldn't retrieve permissions for package:"+packageName);
             return;
         }
         if ((pkgInfo != null) && (pkgInfo.requestedPermissions != null)) {
-            extractPerms(pkgInfo.requestedPermissions, permSet);
+            extractPerms(pkgInfo, permSet, pkgInfo);
         }
     }
-    
-    private void extractPerms(String strList[], Set<PermissionInfo> permSet) {
-        if((strList == null) || (strList.length == 0)) {
+
+    private void extractPerms(PackageInfo info, Set<MyPermissionInfo> permSet,
+            PackageInfo installedPkgInfo) {
+        String[] strList = info.requestedPermissions;
+        int[] flagsList = info.requestedPermissionsFlags;
+        if ((strList == null) || (strList.length == 0)) {
             return;
         }
-        for(String permName:strList) {
+        for (int i=0; i<strList.length; i++) {
+            String permName = strList[i];
+            // If we are only looking at an existing app, then we only
+            // care about permissions that have actually been granted to it.
+            if (installedPkgInfo != null && info == installedPkgInfo) {
+                if ((flagsList[i]&PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
+                    continue;
+                }
+            }
             try {
                 PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0);
-                if(tmpPermInfo != null) {
-                    permSet.add(tmpPermInfo);
+                if (tmpPermInfo == null) {
+                    continue;
                 }
+                int existingIndex = -1;
+                if (installedPkgInfo != null
+                        && installedPkgInfo.requestedPermissions != null) {
+                    for (int j=0; j<installedPkgInfo.requestedPermissions.length; j++) {
+                        if (permName.equals(installedPkgInfo.requestedPermissions[j])) {
+                            existingIndex = j;
+                            break;
+                        }
+                    }
+                }
+                final int existingFlags = existingIndex >= 0 ?
+                        installedPkgInfo.requestedPermissionsFlags[existingIndex] : 0;
+                if (!isDisplayablePermission(tmpPermInfo, flagsList[i], existingFlags)) {
+                    // This is not a permission that is interesting for the user
+                    // to see, so skip it.
+                    continue;
+                }
+                MyPermissionInfo myPerm = new MyPermissionInfo(tmpPermInfo);
+                myPerm.mNewReqFlags = flagsList[i];
+                myPerm.mExistingReqFlags = existingFlags;
+                // This is a new permission if the app is already installed and
+                // doesn't currently hold this permission.
+                myPerm.mNew = installedPkgInfo != null
+                        && (existingFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0;
+                permSet.add(myPerm);
             } catch (NameNotFoundException e) {
                 Log.i(TAG, "Ignoring unknown permission:"+permName);
             }
@@ -210,6 +295,7 @@
         mShowMore = mPermsView.findViewById(R.id.show_more);
         mShowMoreIcon = (ImageView) mShowMore.findViewById(R.id.show_more_icon);
         mShowMoreText = (TextView) mShowMore.findViewById(R.id.show_more_text);
+        mNewList = (LinearLayout) mPermsView.findViewById(R.id.new_perms_list);
         mDangerousList = (LinearLayout) mPermsView.findViewById(R.id.dangerous_perms_list);
         mNonDangerousList = (LinearLayout) mPermsView.findViewById(R.id.non_dangerous_perms_list);
         mNoPermsView = mPermsView.findViewById(R.id.no_permissions);
@@ -222,6 +308,7 @@
         // Pick up from framework resources instead.
         mDefaultGrpLabel = mContext.getString(R.string.default_permission_group);
         mPermFormat = mContext.getString(R.string.permissions_format);
+        mNewPermPrefix = mContext.getText(R.string.perms_new_perm_prefix);
         mNormalIcon = mContext.getResources().getDrawable(R.drawable.ic_text_dot);
         mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission);
         mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_close_holo_dark);
@@ -233,39 +320,56 @@
     }
 
     /**
-     * Canonicalizes the group description before it is displayed to the user.
-     *
-     * TODO check for internationalization issues remove trailing '.' in str1
-     */
-    private String canonicalizeGroupDesc(String groupDesc) {
-        if ((groupDesc == null) || (groupDesc.length() == 0)) {
-            return null;
-        }
-        // Both str1 and str2 are non-null and are non-zero in size.
-        int len = groupDesc.length();
-        if(groupDesc.charAt(len-1) == '.') {
-            groupDesc = groupDesc.substring(0, len-1);
-        }
-        return groupDesc;
-    }
-
-    /**
      * Utility method that concatenates two strings defined by mPermFormat.
      * a null value is returned if both str1 and str2 are null, if one of the strings
      * is null the other non null value is returned without formatting
      * this is to placate initial error checks
      */
-    private String formatPermissions(String groupDesc, CharSequence permDesc) {
-        if(groupDesc == null) {
-            if(permDesc == null) {
-                return null;
-            }
-            return permDesc.toString();
-        }
-        groupDesc = canonicalizeGroupDesc(groupDesc);
-        if(permDesc == null) {
+    private CharSequence formatPermissions(CharSequence groupDesc, CharSequence permDesc,
+            boolean newPerms) {
+        if (permDesc == null) {
             return groupDesc;
         }
+        // Sometimes people write permission names with a trailing period;
+        // strip that if it appears.
+        int len = permDesc.length();
+        if (len > 0 && permDesc.charAt(len-1) == '.') {
+            permDesc = (permDesc.toString()).substring(0, len-1);
+        }
+        if (newPerms) {
+            if (true) {
+                // If this is a new permission, format it appropriately.
+                SpannableStringBuilder builder = new SpannableStringBuilder();
+                if (groupDesc != null) {
+                    // The previous permissions go in front, with a newline
+                    // separating them.
+                    builder.append(groupDesc);
+                    builder.append("\n");
+                }
+                Parcel parcel = Parcel.obtain();
+                TextUtils.writeToParcel(mNewPermPrefix, parcel, 0);
+                parcel.setDataPosition(0);
+                CharSequence newStr = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+                parcel.recycle();
+                builder.append(newStr);
+                builder.append(permDesc);
+                return builder;
+            } else {
+                // If this is a new permission, format it appropriately.
+                SpannableStringBuilder builder = new SpannableStringBuilder(permDesc);
+                builder.insert(0, mNewPermPrefix);
+                if (groupDesc != null) {
+                    // The previous permissions go in front, with a newline
+                    // separating them.
+                    builder.insert(0, "\n");
+                    builder.insert(0, groupDesc);
+                }
+                return builder;
+            }
+        }
+        if (groupDesc == null) {
+            return permDesc;
+        }
         // groupDesc and permDesc are non null
         return String.format(mPermFormat, groupDesc, permDesc.toString());
     }
@@ -295,9 +399,8 @@
      * Utility method that displays permissions from a map containing group name and
      * list of permission descriptions.
      */
-    private void displayPermissions(boolean dangerous) {
-        Map<String, String> permInfoMap = dangerous ? mDangerousMap : mNormalMap;
-        LinearLayout permListView = dangerous ? mDangerousList : mNonDangerousList;
+    private void displayPermissions(Map<String, CharSequence> permInfoMap,
+            LinearLayout permListView, boolean dangerous) {
         permListView.removeAllViews();
 
         Set<String> permInfoStrSet = permInfoMap.keySet();
@@ -349,17 +452,20 @@
             break;
 
         case DANGEROUS_ONLY:
-            displayPermissions(true);
+            displayPermissions(mNewMap, mNewList, true);
+            displayPermissions(mDangerousMap, mDangerousList, true);
             break;
 
         case NORMAL_ONLY:
-            displayPermissions(false);
+            displayPermissions(mNewMap, mNewList, true);
+            displayPermissions(mNormalMap, mNonDangerousList, false);
             break;
 
         case BOTH:
-            displayPermissions(true);
+            displayPermissions(mNewMap, mNewList, true);
+            displayPermissions(mDangerousMap, mDangerousList, true);
             if (mExpanded) {
-                displayPermissions(false);
+                displayPermissions(mNormalMap, mNonDangerousList, false);
                 mShowMoreIcon.setImageDrawable(mShowMaxIcon);
                 mShowMoreText.setText(R.string.perms_hide);
                 mNonDangerousList.setVisibility(View.VISIBLE);
@@ -372,22 +478,38 @@
             break;
         }
     }
-    
-    private boolean isDisplayablePermission(PermissionInfo pInfo) {
-        if(pInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS ||
-                pInfo.protectionLevel == PermissionInfo.PROTECTION_NORMAL) {
+
+    private boolean isDisplayablePermission(PermissionInfo pInfo, int newReqFlags,
+            int existingReqFlags) {
+        final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+        // Dangerous and normal permissions are always shown to the user.
+        if (base == PermissionInfo.PROTECTION_DANGEROUS ||
+                base == PermissionInfo.PROTECTION_NORMAL) {
+            return true;
+        }
+        // Development permissions are only shown to the user if they are already
+        // granted to the app -- if we are installing an app and they are not
+        // already granted, they will not be granted as part of the install.
+        // Note we also need the app to have specified this permission is not
+        // required -- this is not technically needed, but it helps various things
+        // if we ensure apps always mark development permissions as option, so that
+        // even not knowing what a permission is we can still know whether it will
+        // be granted to the app when it is installed.
+        if ((existingReqFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
+                && (newReqFlags&PackageInfo.REQUESTED_PERMISSION_REQUIRED) == 0
+                && (pInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
             return true;
         }
         return false;
     }
-    
+
     /*
      * Utility method that aggregates all permission descriptions categorized by group
      * Say group1 has perm11, perm12, perm13, the group description will be
      * perm11_Desc, perm12_Desc, perm13_Desc
      */
-    private void aggregateGroupDescs(
-            Map<String, List<PermissionInfo> > map, Map<String, String> retMap) {
+    private void aggregateGroupDescs(Map<String, List<MyPermissionInfo> > map,
+            Map<String, CharSequence> retMap, boolean newPerms) {
         if(map == null) {
             return;
         }
@@ -397,20 +519,20 @@
         Set<String> grpNames = map.keySet();
         Iterator<String> grpNamesIter = grpNames.iterator();
         while(grpNamesIter.hasNext()) {
-            String grpDesc = null;
+            CharSequence grpDesc = null;
             String grpNameKey = grpNamesIter.next();
-            List<PermissionInfo> grpPermsList = map.get(grpNameKey);
+            List<MyPermissionInfo> grpPermsList = map.get(grpNameKey);
             if(grpPermsList == null) {
                 continue;
             }
             for(PermissionInfo permInfo: grpPermsList) {
                 CharSequence permDesc = permInfo.loadLabel(mPm);
-                grpDesc = formatPermissions(grpDesc, permDesc);
+                grpDesc = formatPermissions(grpDesc, permDesc, newPerms);
             }
             // Insert grpDesc into map
             if(grpDesc != null) {
                 if(localLOGV) Log.i(TAG, "Group:"+grpNameKey+" description:"+grpDesc.toString());
-                retMap.put(grpNameKey, grpDesc.toString());
+                retMap.put(grpNameKey, grpDesc);
             }
         }
     }
@@ -428,42 +550,53 @@
         }
     }
     
-    private void setPermissions(List<PermissionInfo> permList) {
+    private void setPermissions(List<MyPermissionInfo> permList) {
         mGroupLabelCache = new HashMap<String, CharSequence>();
         //add the default label so that uncategorized permissions can go here
         mGroupLabelCache.put(mDefaultGrpName, mDefaultGrpLabel);
         
         // Map containing group names and a list of permissions under that group
+        // that are new from the current install
+        mNewMap = new HashMap<String, CharSequence>();
+        // Map containing group names and a list of permissions under that group
         // categorized as dangerous
-        mDangerousMap = new HashMap<String, String>();
+        mDangerousMap = new HashMap<String, CharSequence>();
         // Map containing group names and a list of permissions under that group
         // categorized as normal
-        mNormalMap = new HashMap<String, String>();
+        mNormalMap = new HashMap<String, CharSequence>();
         
         // Additional structures needed to ensure that permissions are unique under 
         // each group
-        Map<String, List<PermissionInfo>> dangerousMap = 
-            new HashMap<String,  List<PermissionInfo>>();
-        Map<String, List<PermissionInfo> > normalMap = 
-            new HashMap<String,  List<PermissionInfo>>();
+        Map<String, List<MyPermissionInfo>> newMap =
+            new HashMap<String,  List<MyPermissionInfo>>();
+        Map<String, List<MyPermissionInfo>> dangerousMap = 
+            new HashMap<String,  List<MyPermissionInfo>>();
+        Map<String, List<MyPermissionInfo> > normalMap = 
+            new HashMap<String,  List<MyPermissionInfo>>();
         PermissionInfoComparator permComparator = new PermissionInfoComparator(mPm);
         
         if (permList != null) {
             // First pass to group permissions
-            for (PermissionInfo pInfo : permList) {
+            for (MyPermissionInfo pInfo : permList) {
                 if(localLOGV) Log.i(TAG, "Processing permission:"+pInfo.name);
-                if(!isDisplayablePermission(pInfo)) {
+                if(!isDisplayablePermission(pInfo, pInfo.mNewReqFlags, pInfo.mExistingReqFlags)) {
                     if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" is not displayable");
                     continue;
                 }
-                Map<String, List<PermissionInfo> > permInfoMap =
-                    (pInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) ?
-                            dangerousMap : normalMap;
+                Map<String, List<MyPermissionInfo> > permInfoMap;
+                if (pInfo.mNew) {
+                    permInfoMap = newMap;
+                } else if ((pInfo.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE)
+                            == PermissionInfo.PROTECTION_DANGEROUS) {
+                    permInfoMap = dangerousMap;
+                } else {
+                    permInfoMap = normalMap;
+                }
                 String grpName = (pInfo.group == null) ? mDefaultGrpName : pInfo.group;
                 if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" belongs to group:"+grpName);
-                List<PermissionInfo> grpPermsList = permInfoMap.get(grpName);
+                List<MyPermissionInfo> grpPermsList = permInfoMap.get(grpName);
                 if(grpPermsList == null) {
-                    grpPermsList = new ArrayList<PermissionInfo>();
+                    grpPermsList = new ArrayList<MyPermissionInfo>();
                     permInfoMap.put(grpName, grpPermsList);
                     grpPermsList.add(pInfo);
                 } else {
@@ -477,12 +610,13 @@
             }
             // Second pass to actually form the descriptions
             // Look at dangerous permissions first
-            aggregateGroupDescs(dangerousMap, mDangerousMap);
-            aggregateGroupDescs(normalMap, mNormalMap);
+            aggregateGroupDescs(newMap, mNewMap, true);
+            aggregateGroupDescs(dangerousMap, mDangerousMap, false);
+            aggregateGroupDescs(normalMap, mNormalMap, false);
         }
 
         mCurrentState = State.NO_PERMS;
-        if(mDangerousMap.size() > 0) {
+        if (mNewMap.size() > 0 || mDangerousMap.size() > 0) {
             mCurrentState = (mNormalMap.size() > 0) ? State.BOTH : State.DANGEROUS_ONLY;
         } else if(mNormalMap.size() > 0) {
             mCurrentState = State.NORMAL_ONLY;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a4087d5..d6dd15e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2980,8 +2980,7 @@
                           "/" + ss.selEnd + " out of range for " + restored +
                           "text " + mText);
                 } else {
-                    Selection.setSelection((Spannable) mText, ss.selStart,
-                                           ss.selEnd);
+                    Selection.setSelection((Spannable) mText, ss.selStart, ss.selEnd);
 
                     if (ss.frozenWithFocus) {
                         createEditorIfNeeded("restore instance with focus");
@@ -6983,6 +6982,9 @@
      */
     protected void onSelectionChanged(int selStart, int selEnd) {
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
+        // mEditor may be null if selection is created programatically.
+        createEditorIfNeeded("onSelectionChanged");
+        // Invalidate even when selection range is empty, to remove previous highlight
         getEditor().mTextDisplayListIsValid = false;
     }
 
@@ -8201,7 +8203,7 @@
             vibrate = false;
         }
 
-        if (!handled && (mEditor == null || getEditor().mSelectionActionMode != null)) {
+        if (!handled && mEditor != null && getEditor().mSelectionActionMode != null) {
             if (touchPositionIsInSelection()) {
                 // Start a drag
                 final int start = getSelectionStart();
@@ -10363,9 +10365,9 @@
             boolean allowText = getContext().getResources().getBoolean(
                     com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
 
-            mode.setTitle(allowText ?
-                    mContext.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
+            mode.setTitle(mContext.getString(com.android.internal.R.string.textSelectionCABTitle));
             mode.setSubtitle(null);
+            mode.setTitleOptionalHint(true);
 
             int selectAllIconId = 0; // No icon by default
             if (!allowText) {
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index afb5bf1..f3486bd 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -748,6 +748,16 @@
         }
         
         @Override
+        public void setTitleOptionalHint(boolean titleOptional) {
+            mContextView.setTitleOptional(titleOptional);
+        }
+
+        @Override
+        public boolean isTitleOptional() {
+            return mContextView.isTitleOptional();
+        }
+
+        @Override
         public View getCustomView() {
             return mCustomView != null ? mCustomView.get() : null;
         }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 5d80b79..82b2654 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -43,16 +43,17 @@
     void removeClient(in IInputMethodClient client);
             
     InputBindResult startInput(in IInputMethodClient client,
-            IInputContext inputContext, in EditorInfo attribute,
-            boolean initial, boolean needResult);
+            IInputContext inputContext, in EditorInfo attribute, int controlFlags);
     void finishInput(in IInputMethodClient client);
     boolean showSoftInput(in IInputMethodClient client, int flags,
             in ResultReceiver resultReceiver);
     boolean hideSoftInput(in IInputMethodClient client, int flags,
             in ResultReceiver resultReceiver);
-    void windowGainedFocus(in IInputMethodClient client, in IBinder windowToken,
-            boolean viewHasFocus, boolean isTextEditor,
-            int softInputMode, boolean first, int windowFlags);
+    // Report that a window has gained focus.  If 'attribute' is non-null,
+    // this will also do a startInput.
+    InputBindResult windowGainedFocus(in IInputMethodClient client, in IBinder windowToken,
+            int controlFlags, int softInputMode, int windowFlags,
+            in EditorInfo attribute, IInputContext inputContext);
             
     void showInputMethodPickerFromClient(in IInputMethodClient client);
     void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index edf4443..4b681ec 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -72,6 +72,16 @@
     }
 
     @Override
+    public void setTitleOptionalHint(boolean titleOptional) {
+        mContextView.setTitleOptional(titleOptional);
+    }
+
+    @Override
+    public boolean isTitleOptional() {
+        return mContextView.isTitleOptional();
+    }
+
+    @Override
     public void setCustomView(View view) {
         mContextView.setCustomView(view);
         mCustomView = view != null ? new WeakReference<View>(view) : null;
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index fa16527..16f08f5 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -56,6 +56,7 @@
     private int mTitleStyleRes;
     private int mSubtitleStyleRes;
     private Drawable mSplitBackground;
+    private boolean mTitleOptional;
 
     private Animator mCurrentAnimation;
     private boolean mAnimateInOnLayout;
@@ -354,7 +355,18 @@
         }
 
         if (mTitleLayout != null && mCustomView == null) {
-            availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
+            if (mTitleOptional) {
+                final int titleWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+                mTitleLayout.measure(titleWidthSpec, childSpecHeight);
+                final int titleWidth = mTitleLayout.getMeasuredWidth();
+                final boolean titleFits = titleWidth <= availableWidth;
+                if (titleFits) {
+                    availableWidth -= titleWidth;
+                }
+                mTitleLayout.setVisibility(titleFits ? VISIBLE : GONE);
+            } else {
+                availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
+            }
         }
 
         if (mCustomView != null) {
@@ -460,7 +472,7 @@
             }
         }
 
-        if (mTitleLayout != null && mCustomView == null) {
+        if (mTitleLayout != null && mCustomView == null && mTitleLayout.getVisibility() != GONE) {
             x += positionChild(mTitleLayout, x, y, contentHeight);
         }
         
@@ -512,4 +524,15 @@
             super.onInitializeAccessibilityEvent(event);
         }
     }
+
+    public void setTitleOptional(boolean titleOptional) {
+        if (titleOptional != mTitleOptional) {
+            requestLayout();
+        }
+        mTitleOptional = titleOptional;
+    }
+
+    public boolean isTitleOptional() {
+        return mTitleOptional;
+    }
 }
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 2241f60..2beedad 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -101,11 +101,6 @@
     SkScalar h_ = SkFloatToScalar(hOffset);
     SkScalar v_ = SkFloatToScalar(vOffset);
 
-    if (!needsLayout(text, count, bidiFlags)) {
-        canvas->drawTextOnPathHV(text, count << 1, *path, h_, v_, *paint);
-        return;
-    }
-
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
             text, 0, count, count, bidiFlags);
     if (value == NULL) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index cdce4f9..f0560c1 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -521,6 +521,20 @@
     renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
 }
 
+static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
+        SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) {
+    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+            text, 0, count, count, flags);
+    if (value == NULL) {
+        return;
+    }
+    const jchar* glyphs = value->getGlyphs();
+    size_t glyphsCount = value->getGlyphsCount();
+    int bytesCount = glyphsCount * sizeof(jchar);
+    renderer->drawTextOnPath((const char*) glyphs, bytesCount, glyphsCount, path,
+            hOffset, vOffset, paint);
+}
+
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
         int flags, SkPaint* paint) {
@@ -551,6 +565,24 @@
     env->ReleaseStringChars(text, textArray);
 }
 
+static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
+        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
+    jchar* textArray = env->GetCharArrayElements(text, NULL);
+    renderTextOnPath(renderer, textArray + index, count, path,
+            hOffset, vOffset, flags, paint);
+    env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
+}
+
+static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, jstring text, jint start, jint end,
+        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
+    const jchar* textArray = env->GetStringChars(text, NULL);
+    renderTextOnPath(renderer, textArray + start, end - start, path,
+            hOffset, vOffset, flags, paint);
+    env->ReleaseStringChars(text, textArray);
+}
+
 static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
         jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
@@ -885,6 +917,10 @@
     { "nDrawText",          "(ILjava/lang/String;IIFFII)V",
             (void*) android_view_GLES20Canvas_drawText },
 
+    { "nDrawTextOnPath",    "(I[CIIIFFII)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
+    { "nDrawTextOnPath",    "(ILjava/lang/String;IIIFFII)V",
+            (void*) android_view_GLES20Canvas_drawTextOnPath },
+
     { "nDrawTextRun",       "(I[CIIIIFFII)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
     { "nDrawTextRun",       "(ILjava/lang/String;IIIIFFII)V",
             (void*) android_view_GLES20Canvas_drawTextRun },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a2b1117..d4d29ae 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -147,7 +147,7 @@
          @hide -->
     <permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
         android:permissionGroup="android.permission-group.COST_MONEY"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_sendSmsNoConfirmation"
         android:description="@string/permdesc_sendSmsNoConfirmation" />
 
@@ -194,7 +194,7 @@
          @hide Pending API council approval -->
     <permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
         android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_receiveEmergencyBroadcast"
         android:description="@string/permdesc_receiveEmergencyBroadcast" />
 
@@ -383,7 +383,7 @@
 
     <!-- Allows an application to install a location provider into the Location Manager -->
     <permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_installLocationProvider"
         android:description="@string/permdesc_installLocationProvider" />
 
@@ -461,7 +461,7 @@
         @hide -->
     <permission android:name="android.permission.CONNECTIVITY_INTERNAL"
         android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
@@ -559,7 +559,7 @@
          @hide -->
     <permission android:name="android.permission.MANAGE_USB"
         android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_manageUsb"
         android:description="@string/permdesc_manageUsb" />
 
@@ -568,7 +568,7 @@
          @hide -->
     <permission android:name="android.permission.ACCESS_MTP"
         android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_accessMtp"
         android:description="@string/permdesc_accessMtp" />
 
@@ -611,7 +611,7 @@
          Does not include placing calls. -->
     <permission android:name="android.permission.MODIFY_PHONE_STATE"
         android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_modifyPhoneState"
         android:description="@string/permdesc_modifyPhoneState" />
 
@@ -626,7 +626,7 @@
          @hide Used internally. -->
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
         android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
@@ -651,7 +651,7 @@
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_mediaStorageWrite"
         android:description="@string/permdesc_mediaStorageWrite"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- ============================================ -->
     <!-- Permissions for low-level system interaction -->
@@ -675,15 +675,9 @@
         android:label="@string/permlab_writeSettings"
         android:description="@string/permdesc_writeSettings" />
 
-    <!-- Allows an application to read or write the secure system settings. -->
-    <permission android:name="android.permission.WRITE_SECURE_SETTINGS"
-        android:protectionLevel="signatureOrSystem"
-        android:label="@string/permlab_writeSecureSettings"
-        android:description="@string/permdesc_writeSecureSettings" />
-
     <!-- Allows an application to modify the Google service map. -->
     <permission android:name="android.permission.WRITE_GSERVICES"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_writeGservices"
         android:description="@string/permdesc_writeGservices" />
 
@@ -757,19 +751,11 @@
         android:label="@string/permlab_forceStopPackages"
         android:description="@string/permdesc_forceStopPackages" />
 
-    <!-- Allows an application to retrieve state dump information from system
-         services. -->
-    <permission android:name="android.permission.DUMP"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="signatureOrSystem"
-        android:label="@string/permlab_dump"
-        android:description="@string/permdesc_dump" />
-
     <!-- @hide Allows an application to retrieve the content of the active window
          An active window is the window that has fired an accessibility event. -->
     <permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
         android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_retrieve_window_content"
         android:description="@string/permdesc_retrieve_window_content" />
 
@@ -868,7 +854,7 @@
 
     <!-- Allows applications to set the system time -->
     <permission android:name="android.permission.SET_TIME"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_setTime"
         android:description="@string/permdesc_setTime" />
 
@@ -964,7 +950,7 @@
     <!-- Allows applications to write the apn settings -->
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
                 android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-                android:protectionLevel="signatureOrSystem"
+                android:protectionLevel="signature|system"
                 android:description="@string/permdesc_writeApnSettings"
                 android:label="@string/permlab_writeApnSettings" />
 
@@ -1035,7 +1021,7 @@
     <!-- Allows an application to use any media decoder when decoding for playback
          @hide -->
     <permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
-        android:protectionLevel="signatureOrSystem"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_anyCodecForPlayback"
         android:description="@string/permdesc_anyCodecForPlayback" />
 
@@ -1052,6 +1038,21 @@
         android:label="@string/permgrouplab_developmentTools"
         android:description="@string/permgroupdesc_developmentTools" />
 
+    <!-- Allows an application to read or write the secure system settings. -->
+    <permission android:name="android.permission.WRITE_SECURE_SETTINGS"
+        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
+        android:protectionLevel="signature|system|development"
+        android:label="@string/permlab_writeSecureSettings"
+        android:description="@string/permdesc_writeSecureSettings" />
+
+    <!-- Allows an application to retrieve state dump information from system
+         services. -->
+    <permission android:name="android.permission.DUMP"
+        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
+        android:protectionLevel="signature|system|development"
+        android:label="@string/permlab_dump"
+        android:description="@string/permdesc_dump" />
+
     <!-- Configure an application for debugging. -->
     <permission android:name="android.permission.SET_DEBUG_APP"
         android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
@@ -1099,7 +1100,7 @@
     <permission android:name="android.permission.STATUS_BAR"
         android:label="@string/permlab_statusBar"
         android:description="@string/permdesc_statusBar"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to be the status bar.  Currently used only by SystemUI.apk
     @hide -->
@@ -1120,7 +1121,7 @@
     <permission android:name="android.permission.UPDATE_DEVICE_STATS"
         android:label="@string/permlab_batteryStats"
         android:description="@string/permdesc_batteryStats"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to open windows that are for use by parts
          of the system user interface.  Not for use by third party apps. -->
@@ -1160,7 +1161,7 @@
     <permission android:name="android.permission.SHUTDOWN"
         android:label="@string/permlab_shutdown"
         android:description="@string/permdesc_shutdown"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to tell the activity manager to temporarily
          stop application switches, putting it into a special mode that
@@ -1170,7 +1171,7 @@
     <permission android:name="android.permission.STOP_APP_SWITCHES"
         android:label="@string/permlab_stopAppSwitches"
         android:description="@string/permdesc_stopAppSwitches"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to retrieve the current state of keys and
          switches.  This is only for use by the system.-->
@@ -1205,7 +1206,7 @@
     <permission android:name="android.permission.BIND_WALLPAPER"
         android:label="@string/permlab_bindWallpaper"
         android:description="@string/permdesc_bindWallpaper"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Must be required by device administration receiver, to ensure that only the
          system can interact with it. -->
@@ -1232,7 +1233,7 @@
     <permission android:name="android.permission.INSTALL_PACKAGES"
         android:label="@string/permlab_installPackages"
         android:description="@string/permdesc_installPackages"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to clear user data -->
     <permission android:name="android.permission.CLEAR_APP_USER_DATA"
@@ -1244,27 +1245,33 @@
     <permission android:name="android.permission.DELETE_CACHE_FILES"
         android:label="@string/permlab_deleteCacheFiles"
         android:description="@string/permdesc_deleteCacheFiles"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to delete packages. -->
     <permission android:name="android.permission.DELETE_PACKAGES"
         android:label="@string/permlab_deletePackages"
         android:description="@string/permdesc_deletePackages"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to move location of installed package.
          @hide -->
     <permission android:name="android.permission.MOVE_PACKAGE"
         android:label="@string/permlab_movePackage"
         android:description="@string/permdesc_movePackage"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to change whether an application component (other than its own) is
          enabled or not. -->
     <permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
         android:label="@string/permlab_changeComponentState"
         android:description="@string/permdesc_changeComponentState"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
+
+    <!-- @hide Allows an application to grant or revoke specific permissions. -->
+    <permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS"
+        android:label="@string/permlab_grantRevokePermissions"
+        android:description="@string/permdesc_grantRevokePermissions"
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to use SurfaceFlinger's low level features -->
     <permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
@@ -1277,7 +1284,7 @@
     <permission android:name="android.permission.READ_FRAME_BUFFER"
         android:label="@string/permlab_readFrameBuffer"
         android:description="@string/permdesc_readFrameBuffer"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Required to be able to disable the device (very dangerous!). -->
     <permission android:name="android.permission.BRICK"
@@ -1289,7 +1296,7 @@
     <permission android:name="android.permission.REBOOT"
         android:label="@string/permlab_reboot"
         android:description="@string/permdesc_reboot"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
    <!-- Allows low-level access to power management -->
     <permission android:name="android.permission.DEVICE_POWER"
@@ -1329,7 +1336,7 @@
     <permission android:name="android.permission.MASTER_CLEAR"
         android:label="@string/permlab_masterClear"
         android:description="@string/permdesc_masterClear"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to call any phone number, including emergency
          numbers, without going through the Dialer user interface for the user
@@ -1337,34 +1344,34 @@
     <permission android:name="android.permission.CALL_PRIVILEGED"
         android:label="@string/permlab_callPrivileged"
         android:description="@string/permdesc_callPrivileged"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to perform CDMA OTA provisioning @hide -->
     <permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
         android:label="@string/permlab_performCdmaProvisioning"
         android:description="@string/permdesc_performCdmaProvisioning"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows enabling/disabling location update notifications from
          the radio. Not for use by normal applications. -->
     <permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
         android:label="@string/permlab_locationUpdates"
         android:description="@string/permdesc_locationUpdates"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows read/write access to the "properties" table in the checkin
          database, to change values that get uploaded. -->
     <permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"
         android:label="@string/permlab_checkinProperties"
         android:description="@string/permdesc_checkinProperties"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to collect component usage
          statistics @hide -->
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
         android:label="@string/permlab_pkgUsageStats"
         android:description="@string/permdesc_pkgUsageStats"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to collect battery statistics -->
     <permission android:name="android.permission.BATTERY_STATS"
@@ -1377,7 +1384,7 @@
     <permission android:name="android.permission.BACKUP"
         android:label="@string/permlab_backup"
         android:description="@string/permdesc_backup"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows a package to launch the secure full-backup confirmation UI.
          ONLY the system process may hold this permission.
@@ -1392,7 +1399,7 @@
     <permission android:name="android.permission.BIND_REMOTEVIEWS"
         android:label="@string/permlab_bindRemoteViews"
         android:description="@string/permdesc_bindRemoteViews"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to tell the AppWidget service which application
          can access AppWidget's data.  The normal user flow is that a user
@@ -1404,7 +1411,7 @@
         android:permissionGroup="android.permission-group.PERSONAL_INFO"
         android:label="@string/permlab_bindGadget"
         android:description="@string/permdesc_bindGadget"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows applications to change the background data setting
          @hide pending API council -->
@@ -1424,7 +1431,7 @@
          besides global search. -->
     <permission android:name="android.permission.GLOBAL_SEARCH"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Internal permission protecting access to the global search
          system: ensures that only the system can access the provider
@@ -1442,14 +1449,14 @@
          own apk as Ghod Intended. -->
     <permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allow an application to read and write the cache partition.
          @hide -->
     <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
         android:label="@string/permlab_cache_filesystem"
         android:description="@string/permdesc_cache_filesystem"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Must be required by default container service so that only
          the system can bind to it and use it to copy
@@ -1465,14 +1472,14 @@
         @hide
     -->
     <permission android:name="android.permission.CRYPT_KEEPER"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to read historical network usage for
          specific networks and applications. @hide -->
     <permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
         android:label="@string/permlab_readNetworkUsageHistory"
         android:description="@string/permdesc_readNetworkUsageHistory"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to manage network policies (such as warning and disable
          limits) and to define application-specific rules. @hide -->
@@ -1487,7 +1494,7 @@
     <permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
         android:label="@string/permlab_modifyNetworkAccounting"
         android:description="@string/permdesc_modifyNetworkAccounting"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- C2DM permission.
          @hide Used internally.
@@ -1503,7 +1510,7 @@
     <permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
         android:label="@string/permlab_packageVerificationAgent"
         android:description="@string/permdesc_packageVerificationAgent"
-        android:protectionLevel="signatureOrSystem" />
+        android:protectionLevel="signature|system" />
 
     <!-- Must be required by package verifier receiver, to ensure that only the
          system can interact with it.
diff --git a/core/res/res/layout/app_perms_summary.xml b/core/res/res/layout/app_perms_summary.xml
index 3f99dde..77dbc2e 100755
--- a/core/res/res/layout/app_perms_summary.xml
+++ b/core/res/res/layout/app_perms_summary.xml
@@ -32,6 +32,15 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 
+    <!-- List view containing list of new permissions categorized by groups. -->
+    <LinearLayout
+        android:id="@+id/new_perms_list"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:paddingLeft="16dip"
+        android:paddingRight="12dip"
+        android:layout_height="wrap_content" />
+
     <!-- List view containing list of dangerous permissions categorized by groups. -->
     <LinearLayout
         android:id="@+id/dangerous_perms_list"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 92c59ab..4aa7dde 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -157,7 +157,7 @@
              of permission to a requesting application at installation, without
              asking for the user's explicit approval (though the user always
              has the option to review these permissions before installing). -->
-        <enum name="normal" value="0" />
+        <flag name="normal" value="0" />
         <!-- A higher-risk permission that would give a requesting application
              access to private user data or control over the device that can
              negatively impact the user.  Because this type of permission
@@ -167,13 +167,13 @@
              user and require confirmation before proceeding, or some other
              approach may be taken to avoid the user automatically allowing
              the use of such facilities.  -->
-        <enum name="dangerous" value="1" />
+        <flag name="dangerous" value="1" />
         <!-- A permission that the system is to grant only if the requesting
              application is signed with the same certificate as the application
              that declared the permission. If the certificates match, the system
              automatically grants the permission without notifying the user or
              asking for the user's explicit approval. -->
-        <enum name="signature" value="2" />
+        <flag name="signature" value="2" />
         <!-- A permission that the system is to grant only to packages in the
              Android system image <em>or</em> that are signed with the same
              certificates. Please avoid using this option, as the
@@ -183,7 +183,20 @@
              vendors have applications built in to a system image which need
              to share specific features explicitly because they are being built
              together. -->
-        <enum name="signatureOrSystem" value="3" />
+        <flag name="signatureOrSystem" value="3" />
+        <!-- Additional flag from base permission type: this permission can also
+             be granted to any applications installed on the system image.
+             Please avoid using this option, as the
+             signature protection level should be sufficient for most needs and
+             works regardless of exactly where applications are installed.  This
+             permission flag is used for certain special situations where multiple
+             vendors have applications built in to a system image which need
+             to share specific features explicitly because they are being built
+             together. -->
+        <flag name="system" value="0x10" />
+        <!-- Additional flag from base permission type: this permission can also
+             (optionally) be granted to development applications. -->
+        <flag name="development" value="0x20" />
     </attr>
     
     <!-- Specified the name of a group that this permission is associated
@@ -924,6 +937,13 @@
         tag; often this is one of the {@link android.Manifest.permission standard
         system permissions}. -->
         <attr name="name" />
+        <!--  Specify whether this permission is required for the application.
+              The default is true, meaning the application requires the
+              permission, and it must always be granted when it is installed.
+              If you set this to false, then in some cases the application may
+              be installed with it being granted the permission, and it will
+              need to request the permission later if it needs it. -->
+        <attr name="required" format="boolean" />
     </declare-styleable>
 
     <!-- The <code>uses-configuration</code> tag specifies
@@ -966,7 +986,7 @@
               don't support it.  If you set this to false, then this will
               not impose a restriction on where the application can be
               installed. -->
-        <attr name="required" format="boolean" />
+        <attr name="required" />
     </declare-styleable>
 
     <!-- The <code>uses-sdk</code> tag describes the SDK features that the
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0950bdb..94a671d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -115,6 +115,7 @@
   <java-symbol type="id" name="new_app_action" />
   <java-symbol type="id" name="new_app_description" />
   <java-symbol type="id" name="new_app_icon" />
+  <java-symbol type="id" name="new_perms_list" />
   <java-symbol type="id" name="no_permissions" />
   <java-symbol type="id" name="non_dangerous_perms_list" />
   <java-symbol type="id" name="numberpicker_input" />
@@ -629,6 +630,7 @@
   <java-symbol type="string" name="orgTypeWork" />
   <java-symbol type="string" name="passwordIncorrect" />
   <java-symbol type="string" name="permissions_format" />
+  <java-symbol type="string" name="perms_new_perm_prefix" />
   <java-symbol type="string" name="perms_hide" />
   <java-symbol type="string" name="perms_show_all" />
   <java-symbol type="string" name="petabyteShort" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3c1f50d..f548165 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -861,6 +861,14 @@
         possible to get app components into an unusable, inconsistent, or unstable state.
     </string>
 
+    <!-- Title of an application permission for granting or revoking other permissions [CHAR LIMIT=NONE] -->
+    <string name="permlab_grantRevokePermissions">grant or revoke permissions</string>
+    <!-- Description of an application permission for granting or revoking other permissions [CHAR LIMIT=NONE] -->
+    <string name="permdesc_grantRevokePermissions">Allows an application to grant or revoke
+        specific permissions for it or other applications.  Malicious applications may use this
+        to access features you have not granted them.
+    </string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setPreferredApplications">set preferred apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2775,6 +2783,8 @@
     <string name="default_permission_group">Default</string>
     <!-- Do not translate. -->
     <string name="permissions_format"><xliff:g id="perm_line1">%1$s</xliff:g>, <xliff:g id="perm_line2">%2$s</xliff:g></string>
+    <!-- Text that is placed at the front of a permission name that is being added to an app [CHAR LIMIT=NONE] -->
+    <string name="perms_new_perm_prefix"><font size="12" fgcolor="#ffffa3a3">NEW: </font></string>
     <!-- Shown for an application when it doesn't require any permission grants. -->
     <string name="no_permissions">No permissions required</string>
     <!-- When installing an application, the less-dangerous permissions are hidden.  If the user showed those, this is the text to hide them again.  -->
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
index 2cb82e6..c61819d 100755
--- a/drm/java/android/drm/DrmErrorEvent.java
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -24,6 +24,10 @@
  *
  */
 public class DrmErrorEvent extends DrmEvent {
+
+    // Please add newly defined type constants to the end of the list,
+    // and modify checkTypeValidity() accordingly.
+
     /**
      * Something went wrong installing the rights.
      */
@@ -60,28 +64,46 @@
      */
     public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008;
 
+    // Add more type constants here...
+
+    // FIXME:
+    // We may want to add a user-defined type constant, such as
+    // TYPE_VENDOR_SPECIFIC_FAILED, to take care vendor specific use
+    // cases.
+
+
     /**
      * Creates a <code>DrmErrorEvent</code> object with the specified parameters.
      *
      * @param uniqueId Unique session identifier.
-     * @param type Type of the event. Could be any of the event types defined above.
-     * @param message Message description.
+     * @param type Type of the event. Must be any of the event types defined above.
+     * @param message Message description. It can be null.
      */
     public DrmErrorEvent(int uniqueId, int type, String message) {
         super(uniqueId, type, message);
+        checkTypeValidity(type);
     }
 
     /**
      * Creates a <code>DrmErrorEvent</code> object with the specified parameters.
      *
      * @param uniqueId Unique session identifier.
-     * @param type Type of the event. Could be any of the event types defined above.
+     * @param type Type of the event. Must be any of the event types defined above.
      * @param message Message description.
      * @param attributes Attributes for extensible information. Could be any
-     * information provided by the plug-in.
+     * information provided by the plug-in. It can be null.
      */
     public DrmErrorEvent(int uniqueId, int type, String message,
                             HashMap<String, Object> attributes) {
         super(uniqueId, type, message, attributes);
+        checkTypeValidity(type);
+    }
+
+    private void checkTypeValidity(int type) {
+        if (type < TYPE_RIGHTS_NOT_INSTALLED ||
+            type > TYPE_ACQUIRE_DRM_INFO_FAILED) {
+            final String msg = "Unsupported type: " + type;
+            throw new IllegalArgumentException(msg);
+        }
     }
 }
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
index 4053eb3..1a19f5c 100755
--- a/drm/java/android/drm/DrmEvent.java
+++ b/drm/java/android/drm/DrmEvent.java
@@ -23,6 +23,10 @@
  *
  */
 public class DrmEvent {
+
+    // Please do not add type constants in this class. More event type constants
+    // should go to DrmInfoEvent or DrmErrorEvent classes.
+
     /**
      * All of the rights information associated with all DRM schemes have been successfully removed.
      */
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
index 67aa0a9..2826dce 100755
--- a/drm/java/android/drm/DrmInfoEvent.java
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -24,6 +24,10 @@
  *
  */
 public class DrmInfoEvent extends DrmEvent {
+
+    // Please add newly defined type constants to the end of the list,
+    // and modify checkTypeValidity() accordingly.
+
     /**
      * The registration has already been done by another account ID.
      */
@@ -50,29 +54,57 @@
      */
     public static final int TYPE_RIGHTS_REMOVED = 6;
 
+    // Add more type constants here...
+
+    // FIXME:
+    // We may want to add a user-defined type constant, such as
+    // TYPE_VENDOR_SPECIFIC, to take care vendor specific use
+    // cases.
+
     /**
      * Creates a <code>DrmInfoEvent</code> object with the specified parameters.
      *
      * @param uniqueId Unique session identifier.
-     * @param type Type of the event. Could be any of the event types defined above.
-     * @param message Message description.
+     * @param type Type of the event. Must be any of the event types defined above,
+     * or the constants defined in {@link DrmEvent}.
+     * @param message Message description. It can be null.
      */
     public DrmInfoEvent(int uniqueId, int type, String message) {
         super(uniqueId, type, message);
+        checkTypeValidity(type);
     }
 
     /**
      * Creates a <code>DrmInfoEvent</code> object with the specified parameters.
      *
      * @param uniqueId Unique session identifier.
-     * @param type Type of the event. Could be any of the event types defined above.
-     * @param message Message description.
+     * @param type Type of the event. Must be any of the event types defined above,
+     * or the constants defined in {@link DrmEvent}
+     * @param message Message description. It can be null.
      * @param attributes Attributes for extensible information. Could be any
      * information provided by the plug-in.
      */
     public DrmInfoEvent(int uniqueId, int type, String message,
                             HashMap<String, Object> attributes) {
         super(uniqueId, type, message, attributes);
+        checkTypeValidity(type);
+    }
+
+    /*
+     * Check the validity of the given type.
+     * To overcome a design flaw, we need also accept the type constants
+     * defined in super class, DrmEvent.
+     */
+    private void checkTypeValidity(int type) {
+        if (type < TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT ||
+            type > TYPE_RIGHTS_REMOVED) {
+
+            if (type != TYPE_ALL_RIGHTS_REMOVED &&
+                type != TYPE_DRM_INFO_PROCESSED) {
+                final String msg = "Unsupported type: " + type;
+                throw new IllegalArgumentException(msg);
+            }
+        }
     }
 }
 
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 9a7194c..14d5fae 100755
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -317,6 +317,7 @@
      *
      * @return A {@link android.content.ContentValues} instance that contains
      * key-value pairs representing the constraints. Null in case of failure.
+     * The keys are defined in {@link DrmStore.ConstraintsColumns}.
      */
     public ContentValues getConstraints(String path, int action) {
         if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
diff --git a/drm/java/android/drm/DrmStore.java b/drm/java/android/drm/DrmStore.java
index ae311de..2f004cf 100755
--- a/drm/java/android/drm/DrmStore.java
+++ b/drm/java/android/drm/DrmStore.java
@@ -23,45 +23,65 @@
 public class DrmStore {
     /**
      * Interface definition for the columns that represent DRM constraints.
+     * {@link android.drm.DrmManagerClient#getConstraints DrmManagerClient.getConstraints()}
+     * can be called by an application to find out the contraints on the
+     * {@link android.drm.DrmStore.Action actions} that can be performed
+     * on right-protected content. The constants defined in this interface
+     * represent three most common types of constraints: count-based,
+     * date-based, and duration-based. Two or more constraints can be used
+     * at the same time to represent more sophisticated constraints.
+     * In addition, user-defined constraint,
+     * {@link #EXTENDED_METADATA extended metadata}, can be
+     * used if these three types of constraints are not sufficient.
      */
     public interface ConstraintsColumns {
         /**
-         * The maximum repeat count.
+         * This is a count-based constraint. It represents the maximum
+         * repeat count that can be performed on an
+         * {@link android.drm.DrmStore.Action action}.
          * <p>
          * Type: INTEGER
          */
         public static final String MAX_REPEAT_COUNT = "max_repeat_count";
 
         /**
-         * The remaining repeat count.
+         * This is a count-based constraint. It represents the remaining
+         * repeat count that can be performed on an
+         * {@link android.drm.DrmStore.Action action}.
          * <p>
          * Type: INTEGER
          */
         public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
 
         /**
-         * The time before which the rights-protected file cannot be played/viewed.
+         * This is a date-based constraint. It represents the time before which
+         * an {@link android.drm.DrmStore.Action action} can be performed on
+         * the rights-protected content.
          * <p>
          * Type: TEXT
          */
         public static final String LICENSE_START_TIME = "license_start_time";
 
         /**
-         * The time after which the rights-protected file cannot be played/viewed.
+         * This is a date-based constaint. It represents the time after which
+         * an {@link android.drm.DrmStore.Action action} can not be performed on
+         * the rights-protected content.
          * <p>
          * Type: TEXT
          */
         public static final String LICENSE_EXPIRY_TIME = "license_expiry_time";
 
         /**
-         * The available time left before the license expires.
+         * This is a duration-based constaint. It represents the available time left
+         * before the license expires.
          * <p>
          * Type: TEXT
          */
         public static final String LICENSE_AVAILABLE_TIME = "license_available_time";
 
         /**
-         * The data stream for extended metadata.
+         * This is a user-defined constraint. It represents the additional constraint
+         * using extended metadata.
          * <p>
          * Type: TEXT
          */
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 9517513..6921f37 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -17,6 +17,7 @@
 package android.renderscript;
 
 import java.lang.reflect.Field;
+import java.io.File;
 
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -82,6 +83,25 @@
     native void nContextInitToClient(int con);
     native void nContextDeinitToClient(int con);
 
+    /**
+     * Name of the file that holds the object cache.
+     */
+    private static final String CACHE_PATH = "com.android.renderscript.cache";
+    static String mCachePath;
+
+     /**
+     * Sets the directory to use as a persistent storage for the
+     * renderscript object file cache.
+     *
+     * @hide
+     * @param cacheDir A directory the current process can write to
+     */
+    public static void setupDiskCache(File cacheDir) {
+        File f = new File(cacheDir, CACHE_PATH);
+        mCachePath = f.getAbsolutePath();
+        f.mkdirs();
+    }
+
 
     // Methods below are wrapped to protect the non-threadsafe
     // lockless fifo.
@@ -884,7 +904,9 @@
     }
 
     RenderScript(Context ctx) {
-        mApplicationContext = ctx.getApplicationContext();
+        if (ctx != null) {
+            mApplicationContext = ctx.getApplicationContext();
+        }
     }
 
     /**
@@ -896,21 +918,16 @@
         return mApplicationContext;
     }
 
-    static int getTargetSdkVersion(Context ctx) {
-        return ctx.getApplicationInfo().targetSdkVersion;
-    }
-
     /**
      * Create a basic RenderScript context.
      *
+     * @hide
      * @param ctx The context.
      * @return RenderScript
      */
-    public static RenderScript create(Context ctx) {
+    public static RenderScript create(Context ctx, int sdkVersion) {
         RenderScript rs = new RenderScript(ctx);
 
-        int sdkVersion = getTargetSdkVersion(ctx);
-
         rs.mDev = rs.nDeviceCreate();
         rs.mContext = rs.nContextCreate(rs.mDev, 0, sdkVersion);
         if (rs.mContext == 0) {
@@ -922,6 +939,17 @@
     }
 
     /**
+     * Create a basic RenderScript context.
+     *
+     * @param ctx The context.
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx) {
+        int v = ctx.getApplicationInfo().targetSdkVersion;
+        return create(ctx, v);
+    }
+
+    /**
      * Print the currently available debugging information about the state of
      * the RS context to the log.
      *
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
index 2cfeb17..1b2ac90 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -166,7 +166,7 @@
         super(ctx);
         mSurfaceConfig = new SurfaceConfig(sc);
 
-        int sdkVersion = getTargetSdkVersion(ctx);
+        int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
 
         mWidth = 0;
         mHeight = 0;
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index 90f959f..108b230 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -92,13 +92,9 @@
             throw new Resources.NotFoundException();
         }
 
-        // E.g, /system/apps/Fountain.apk
-        //String packageName = rs.getApplicationContext().getPackageResourcePath();
-        // For res/raw/fountain.bc, it wil be /com.android.fountain:raw/fountain
         String resName = resources.getResourceEntryName(resourceID);
-        String cacheDir = rs.getApplicationContext().getCacheDir().toString();
 
         Log.v(TAG, "Create script for resource = " + resName);
-        return rs.nScriptCCreate(resName, cacheDir, pgm, pgmLength);
+        return rs.nScriptCCreate(resName, rs.mCachePath, pgm, pgmLength);
     }
 }
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f9088ac..8153823 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -61,6 +61,7 @@
     "DrawLines",
     "DrawPoints",
     "DrawText",
+    "DrawTextOnPath",
     "DrawPosText",
     "ResetShader",
     "SetupShader",
@@ -483,7 +484,7 @@
             break;
             case DrawText: {
                 getText(&text);
-                int count = getInt();
+                int32_t count = getInt();
                 float x = getFloat();
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
@@ -492,6 +493,17 @@
                     text.text(), text.length(), count, x, y, paint, length);
             }
             break;
+            case DrawTextOnPath: {
+                getText(&text);
+                int32_t count = getInt();
+                SkPath* path = getPath();
+                float hOffset = getFloat();
+                float vOffset = getFloat();
+                SkPaint* paint = getPaint(renderer);
+                ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
+                    text.text(), text.length(), count, paint);
+            }
+            break;
             case DrawPosText: {
                 getText(&text);
                 int count = getInt();
@@ -890,6 +902,19 @@
                 renderer.drawText(text.text(), text.length(), count, x, y, paint, length);
             }
             break;
+            case DrawTextOnPath: {
+                getText(&text);
+                int32_t count = getInt();
+                SkPath* path = getPath();
+                float hOffset = getFloat();
+                float vOffset = getFloat();
+                SkPaint* paint = getPaint(renderer);
+                DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
+                    text.text(), text.length(), count, paint);
+                renderer.drawTextOnPath(text.text(), text.length(), count, path,
+                        hOffset, vOffset, paint);
+            }
+            break;
             case DrawPosText: {
                 getText(&text);
                 int32_t count = getInt();
@@ -1331,6 +1356,19 @@
     addSkip(location);
 }
 
+void DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
+        SkPath* path, float hOffset, float vOffset, SkPaint* paint) {
+    if (!text || count <= 0) return;
+    addOp(DisplayList::DrawTextOnPath);
+    addText(text, bytesCount);
+    addInt(count);
+    addPath(path);
+    addFloat(hOffset);
+    addFloat(vOffset);
+    paint->setAntiAlias(true);
+    addPaint(paint);
+}
+
 void DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (!text || count <= 0) return;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 4a299c6..5d1b460 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -99,6 +99,7 @@
         DrawLines,
         DrawPoints,
         DrawText,
+        DrawTextOnPath,
         DrawPosText,
         ResetShader,
         SetupShader,
@@ -310,6 +311,8 @@
     virtual void drawPoints(float* points, int count, SkPaint* paint);
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
             SkPaint* paint, float length = 1.0f);
+    virtual void drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
+            float hOffset, float vOffset, SkPaint* paint);
     virtual void drawPosText(const char* text, int bytesCount, int count, const float* positions,
             SkPaint* paint);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 55e2ca5..ebb6d88 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <SkCanvas.h>
+#include <SkPathMeasure.h>
 #include <SkTypeface.h>
 
 #include <utils/Log.h>
@@ -2292,6 +2293,76 @@
     drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
 }
 
+void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
+        float hOffset, float vOffset, SkPaint* paint) {
+    if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
+            (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
+        return;
+    }
+
+    float x = 0.0f;
+    float y = 0.0f;
+
+    const bool pureTranslate = mSnapshot->transform->isPureTranslate();
+    if (CC_LIKELY(pureTranslate)) {
+        x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
+        y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
+    }
+
+    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
+    fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
+            paint->getTextSize());
+
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    mCaches.activeTexture(0);
+    setupDraw();
+    setupDrawDirtyRegionsDisabled();
+    setupDrawWithTexture(true);
+    setupDrawAlpha8Color(paint->getColor(), alpha);
+    setupDrawColorFilter();
+    setupDrawShader();
+    setupDrawBlending(true, mode);
+    setupDrawProgram();
+    setupDrawModelView(x, y, x, y, pureTranslate, true);
+    setupDrawTexture(fontRenderer.getTexture(true));
+    setupDrawPureColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawShaderUniforms(pureTranslate);
+
+//    mat4 pathTransform;
+//    pathTransform.loadTranslate(hOffset, vOffset, 0.0f);
+//
+//    float offset = 0.0f;
+//    SkPathMeasure pathMeasure(*path, false);
+//
+//    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
+//        SkScalar pathLength = pathMeasure.getLength();
+//        if (paint->getTextAlign() == SkPaint::kCenter_Align) {
+//            pathLength = SkScalarHalf(pathLength);
+//        }
+//        offset += SkScalarToFloat(pathLength);
+//    }
+
+//        SkScalar x;
+//        SkPath      tmp;
+//        SkMatrix    m(scaledMatrix);
+//
+//        m.postTranslate(xpos + hOffset, 0);
+//        if (matrix) {
+//            m.postConcat(*matrix);
+//        }
+//        morphpath(&tmp, *iterPath, meas, m);
+//        if (fDevice) {
+//            fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true);
+//        } else {
+//            this->drawPath(tmp, iter.getPaint(), NULL, true);
+//        }
+//    }
+}
+
 void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3f63c3fe..4d7a491 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -124,8 +124,10 @@
     virtual void drawPoints(float* points, int count, SkPaint* paint);
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
             SkPaint* paint, float length = -1.0f);
-    virtual void drawPosText(const char* text, int bytesCount, int count, const float* positions,
-            SkPaint* paint);
+    virtual void drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
+            float hOffset, float vOffset, SkPaint* paint);
+    virtual void drawPosText(const char* text, int bytesCount, int count,
+            const float* positions, SkPaint* paint);
 
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
diff --git a/libs/rs/Allocation.cpp b/libs/rs/Allocation.cpp
index 46df171..d69c55f 100644
--- a/libs/rs/Allocation.cpp
+++ b/libs/rs/Allocation.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libRS_cpp"
+
 #include <utils/Log.h>
 #include <malloc.h>
 
diff --git a/libs/rs/BaseObj.cpp b/libs/rs/BaseObj.cpp
index 66e6fac..82e51e7 100644
--- a/libs/rs/BaseObj.cpp
+++ b/libs/rs/BaseObj.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libRS_cpp"
 
 #include <rs.h>
 
diff --git a/libs/rs/Element.cpp b/libs/rs/Element.cpp
index d193892..f318d40 100644
--- a/libs/rs/Element.cpp
+++ b/libs/rs/Element.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libRS_cpp"
+
 #include <utils/Log.h>
 #include <malloc.h>
 #include <string.h>
diff --git a/libs/rs/RenderScript.cpp b/libs/rs/RenderScript.cpp
index 39f1024..0b42055 100644
--- a/libs/rs/RenderScript.cpp
+++ b/libs/rs/RenderScript.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libRS_cpp"
+
 #include <utils/Log.h>
 #include <malloc.h>
 #include <string.h>
diff --git a/libs/rs/Script.cpp b/libs/rs/Script.cpp
index b6112dd..25fa673 100644
--- a/libs/rs/Script.cpp
+++ b/libs/rs/Script.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libRS_cpp"
+
 #include <utils/Log.h>
 #include <malloc.h>
 
diff --git a/libs/rs/ScriptC.cpp b/libs/rs/ScriptC.cpp
index 53d75b8..ad82ff4 100644
--- a/libs/rs/ScriptC.cpp
+++ b/libs/rs/ScriptC.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libRS_cpp"
+
 #include <utils/Log.h>
 #include <malloc.h>
 
diff --git a/libs/rs/ScriptC.h b/libs/rs/ScriptC.h
index 25f00ec..dcbbe10 100644
--- a/libs/rs/ScriptC.h
+++ b/libs/rs/ScriptC.h
@@ -24,7 +24,6 @@
 
 class ScriptC : public Script {
 protected:
-    ScriptC(RenderScript *rs, void *txt, size_t len);
     ScriptC(RenderScript *rs,
             const char *codeTxt, size_t codeLength,
             const char *cachedName, size_t cachedNameLength,
diff --git a/libs/rs/Type.cpp b/libs/rs/Type.cpp
index 3249f97..1352bd7 100644
--- a/libs/rs/Type.cpp
+++ b/libs/rs/Type.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libRS_cpp"
+
 #include <utils/Log.h>
 #include <malloc.h>
 #include <string.h>
@@ -124,7 +126,6 @@
 }
 
 const Type * Type::Builder::create() {
-    ALOGE(" %i %i %i %i %i", mDimX, mDimY, mDimZ, mDimFaces, mDimMipmaps);
     if (mDimZ > 0) {
         if ((mDimX < 1) || (mDimY < 1)) {
             ALOGE("Both X and Y dimension required when Z is present.");
diff --git a/libs/rs/tests/Android.mk b/libs/rs/tests/Android.mk
index a773e84..197e862 100644
--- a/libs/rs/tests/Android.mk
+++ b/libs/rs/tests/Android.mk
@@ -2,7 +2,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	compute.cpp
+	compute.cpp \
+	ScriptC_mono.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libRS \
diff --git a/libs/rs/tests/ScriptC_mono.cpp b/libs/rs/tests/ScriptC_mono.cpp
new file mode 100644
index 0000000..7f83616
--- /dev/null
+++ b/libs/rs/tests/ScriptC_mono.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008-2012 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.
+ */
+
+#include "ScriptC_mono.h"
+
+static const char mono[] = \
+    "\xDE\xC0\x17\x0B\x00\x00\x00\x00\x18\x00\x00\x00\xFC\x03\x00\x00\x00\x00\x00\x00" \
+    "\x10\x00\x00\x00\x42\x43\xC0\xDE\x21\x0C\x00\x00\xFC\x00\x00\x00\x01\x10\x00\x00" \
+    "\x12\x00\x00\x00\x07\x81\x23\x91\x41\xC8\x04\x49\x06\x10\x32\x39\x92\x01\x84\x0C" \
+    "\x25\x05\x08\x19\x1E\x04\x8B\x62\x80\x14\x45\x02\x42\x92\x0B\x42\xA4\x10\x32\x14" \
+    "\x38\x08\x18\x49\x0A\x32\x44\x24\x48\x0A\x90\x21\x23\xC4\x52\x80\x0C\x19\x21\x72" \
+    "\x24\x07\xC8\x48\x11\x62\xA8\xA0\xA8\x40\xC6\xF0\x01\x00\x00\x00\x49\x18\x00\x00" \
+    "\x08\x00\x00\x00\x0B\x8C\x00\x04\x41\x10\x04\x09\x01\x04\x41\x10\x04\x89\xFF\xFF" \
+    "\xFF\xFF\x1F\xC0\x60\x81\xF0\xFF\xFF\xFF\xFF\x03\x18\x00\x00\x00\x89\x20\x00\x00" \
+    "\x13\x00\x00\x00\x32\x22\x48\x09\x20\x64\x85\x04\x93\x22\xA4\x84\x04\x93\x22\xE3" \
+    "\x84\xA1\x90\x14\x12\x4C\x8A\x8C\x0B\x84\xA4\x4C\x10\x48\x23\x00\x73\x04\xC8\x30" \
+    "\x02\x11\x90\x28\x03\x18\x83\xC8\x0C\xC0\x30\x02\x61\x14\xE1\x08\x42\xC3\x08\x83" \
+    "\x51\x06\xA3\x14\xAD\x22\x08\x45\x6D\x20\x60\x8E\x00\x0C\x86\x11\x06\x08\x00\x00" \
+    "\x13\xB0\x70\x90\x87\x76\xB0\x87\x3B\x68\x03\x77\x78\x07\x77\x28\x87\x36\x60\x87" \
+    "\x74\x70\x87\x7A\xC0\x87\x36\x38\x07\x77\xA8\x87\x72\x08\x07\x71\x48\x87\x0D\xF2" \
+    "\x50\x0E\x6D\x00\x0F\x7A\x30\x07\x72\xA0\x07\x73\x20\x07\x7A\x30\x07\x72\xD0\x06" \
+    "\xE9\x10\x07\x7A\x80\x07\x7A\x80\x07\x6D\x90\x0E\x78\xA0\x07\x78\xA0\x07\x78\xD0" \
+    "\x06\xE9\x10\x07\x76\xA0\x07\x71\x60\x07\x7A\x10\x07\x76\xD0\x06\xE9\x30\x07\x72" \
+    "\xA0\x07\x73\x20\x07\x7A\x30\x07\x72\xD0\x06\xE9\x60\x07\x74\xA0\x07\x76\x40\x07" \
+    "\x7A\x60\x07\x74\xD0\x06\xE6\x30\x07\x72\xA0\x07\x73\x20\x07\x7A\x30\x07\x72\xD0" \
+    "\x06\xE6\x60\x07\x74\xA0\x07\x76\x40\x07\x7A\x60\x07\x74\xD0\x06\xF6\x60\x07\x74" \
+    "\xA0\x07\x76\x40\x07\x7A\x60\x07\x74\xD0\x06\xF6\x10\x07\x72\x80\x07\x7A\x60\x07" \
+    "\x74\xA0\x07\x71\x20\x07\x78\xD0\x06\xE1\x00\x07\x7A\x00\x07\x7A\x60\x07\x74\xD0" \
+    "\x06\xEE\x30\x07\x72\xD0\x06\xB3\x60\x07\x74\x30\x44\x29\x00\x00\x08\x00\x00\x00" \
+    "\x80\x21\x4A\x02\x04\x00\x00\x00\x00\x00\x0C\x51\x18\x20\x00\x00\x00\x00\x00\x60" \
+    "\x88\xE2\x00\x01\x00\x00\x00\x00\x00\x79\x18\x00\x45\x00\x00\x00\x43\x88\x27\x78" \
+    "\x84\x05\x87\x3D\x94\x83\x3C\xCC\x43\x3A\xBC\x83\x3B\x2C\x08\xE2\x60\x08\xF1\x10" \
+    "\x4F\xB1\x20\x52\x87\x70\xB0\x87\x70\xF8\x05\x78\x08\x87\x71\x58\x87\x70\x38\x87" \
+    "\x72\xF8\x05\x77\x08\x87\x76\x28\x87\x05\x63\x30\x0E\xEF\xD0\x0E\x6E\x50\x0E\xF8" \
+    "\x10\x0E\xED\x00\x0F\xEC\x50\x0E\x6E\x10\x0E\xEE\x40\x0E\xF2\xF0\x0E\xE9\x40\x0E" \
+    "\x6E\x20\x0F\xF3\xE0\x06\xE8\x50\x0E\xEC\xC0\x0E\xEF\x30\x0E\xEF\xD0\x0E\xF0\x50" \
+    "\x0F\xF4\x50\x0E\x43\x84\xE7\x58\x40\xC8\xC3\x3B\xBC\x03\x3D\x0C\x11\x9E\x64\x41" \
+    "\x30\x07\x43\x88\x67\x79\x98\x05\xCF\x3B\xB4\x83\x3B\xA4\x03\x3C\xBC\x03\x3D\x94" \
+    "\x83\x3B\xD0\x03\x18\x8C\x03\x3A\x84\x83\x3C\x0C\x21\x9E\x06\x00\x16\x44\xB3\x90" \
+    "\x0E\xED\x00\x0F\xEC\x50\x0E\x60\x30\x0A\x6F\x30\x0A\x6B\xB0\x06\x60\x40\x0B\xA2" \
+    "\x10\x0A\xA1\x30\xE2\x18\x03\x78\x90\x87\x70\x38\x87\x76\x08\x87\x29\x02\x30\x8C" \
+    "\xB8\xC6\x40\x1E\xE6\xE1\x17\xCA\x01\x1F\xE0\xE1\x1D\xE4\x81\x1E\x7E\xC1\x1C\xDE" \
+    "\x41\x1E\xCA\x21\x1C\xC6\x01\x1D\x7E\xC1\x1D\xC2\xA1\x1D\xCA\x61\x4A\x60\x8C\x90" \
+    "\xC6\x40\x1E\xE6\xE1\x17\xCA\x01\x1F\xE0\xE1\x1D\xE4\x81\x1E\x7E\xC1\x1C\xDE\x41" \
+    "\x1E\xCA\x21\x1C\xC6\x01\x1D\xA6\x04\x08\x00\x00\x61\x20\x00\x00\x24\x00\x00\x00" \
+    "\x13\x04\x41\x2C\x10\x00\x00\x00\x0C\x00\x00\x00\x04\x8B\xA0\x04\x46\x00\xE8\xCC" \
+    "\x00\x90\x9A\x01\x98\x63\x70\x1A\x86\xCC\x18\x41\x6D\xFA\xB2\xEF\x8D\x11\x88\x6D" \
+    "\xCC\xC6\xDF\x18\xC1\x49\x97\x72\xFA\x51\x9C\x63\x40\x0E\x63\x04\x00\x00\x00\x00" \
+    "\x44\x8C\x11\x03\x42\x08\x82\x68\x90\x41\x4A\x9E\x11\x83\x42\x08\x84\x69\x99\x63" \
+    "\x50\x28\x64\x90\xA1\x52\xA0\x11\x03\x42\x08\x06\x6B\x30\xA2\xB8\x06\x00\xC3\x81" \
+    "\x00\x00\x00\x00\x03\x00\x00\x00\x46\x40\x54\x3F\xD2\x58\x41\x51\xFD\x0E\x35\x01" \
+    "\x01\x31\x00\x00\x03\x00\x00\x00\x5B\x06\x20\x50\xB6\x0C\x47\xA0\x00\x00\x00\x00" \
+    "\x00\x00\x00\x00\x79\x18\x00\x00\x0B\x00\x00\x00\x33\x08\x80\x1C\xC4\xE1\x1C\x66" \
+    "\x14\x01\x3D\x88\x43\x38\x84\xC3\x8C\x42\x80\x07\x79\x78\x07\x73\x98\xB1\x0C\xE6" \
+    "\x00\x0F\xE1\x30\x0E\xE3\x50\x0F\xF2\x10\x0E\xE3\x90\x0F\x00\x00\x71\x20\x00\x00" \
+    "\x0E\x00\x00\x00\x06\x40\x44\x8E\x33\x59\x40\x14\x49\x6E\xF3\x00\x82\xC2\x39\x8B" \
+    "\x13\xF1\x3C\xCF\x9B\x40\xF3\xCF\xF7\xE0\x4C\x5D\x75\xFF\x05\xFB\xDB\x80\xF6\xCF" \
+    "\xF5\x1E\x49\x29\x20\x28\x9C\xB3\x38\x51\xEB\xF0\x3C\xCF\x77\xD5\xFD\x17\x00\x00" \
+    "\x00\x00\x00\x00";
+
+
+ScriptC_mono::ScriptC_mono(RenderScript *rs, const char *cacheDir, size_t cacheDirLength) :
+    ScriptC(rs, mono, sizeof(mono) - 1, "mono", 4, cacheDir, cacheDirLength) {
+
+    printf("sizeof text %i", sizeof(mono));
+
+
+
+}
+
+void ScriptC_mono::forEach_root(const Allocation *ain, const Allocation *aout) {
+    forEach(0, ain, aout, NULL, 0);
+}
+
diff --git a/libs/rs/tests/ScriptC_mono.h b/libs/rs/tests/ScriptC_mono.h
new file mode 100644
index 0000000..7e4f601
--- /dev/null
+++ b/libs/rs/tests/ScriptC_mono.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008-2012 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.
+ */
+
+#include "ScriptC.h"
+
+class ScriptC_mono : protected ScriptC {
+public:
+    ScriptC_mono(RenderScript *rs, const char *cacheDir, size_t cacheDirLength);
+
+    void forEach_root(const Allocation *ain, const Allocation *aout);
+
+};
+
diff --git a/libs/rs/tests/compute.cpp b/libs/rs/tests/compute.cpp
index 28b135f..42eaa52 100644
--- a/libs/rs/tests/compute.cpp
+++ b/libs/rs/tests/compute.cpp
@@ -4,6 +4,8 @@
 #include "Type.h"
 #include "Allocation.h"
 
+#include "ScriptC_mono.h"
+
 int main(int argc, char** argv)
 {
 
@@ -23,12 +25,31 @@
     printf("Type %p\n", t);
 
 
-    const Allocation *a1 = Allocation::createSized(rs, e, 1000);
+    Allocation *a1 = Allocation::createSized(rs, e, 1000);
     printf("Allocation %p\n", a1);
 
+    Allocation *ain = Allocation::createTyped(rs, t);
+    Allocation *aout = Allocation::createTyped(rs, t);
+    printf("Allocation %p %p\n", ain, aout);
+
+    ScriptC_mono * sc = new ScriptC_mono(rs, NULL, 0);
+    printf("new script\n");
+
+    uint32_t *buf = new uint32_t[t->getCount()];
+    for (uint32_t ct=0; ct < t->getCount(); ct++) {
+        buf[ct] = ct | (ct << 16);
+    }
+    //ain->copy1DRangeFrom(0, 128*128, (int32_t *)buf, 128*128*4);
+    ain->copy1DRangeFromUnchecked(0, t->getCount(), buf, t->getCount()*4);
+
+
+
+    sc->forEach_root(ain, aout);
+    printf("for each done\n");
 
 
     printf("Deleting stuff\n");
+    delete sc;
     delete t;
     delete a1;
     delete e;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2c3329e..d522091 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1973,6 +1973,23 @@
 #endif
 };
 
+void AudioFlinger::PlaybackThread::checkSilentMode_l()
+{
+    if (!mMasterMute) {
+        char value[PROPERTY_VALUE_MAX];
+        if (property_get("ro.audio.silent", value, "0") > 0) {
+            char *endptr;
+            unsigned long ul = strtoul(value, &endptr, 0);
+            if (*endptr == '\0' && ul != 0) {
+                ALOGD("Silence is golden");
+                // The setprop command will not allow a property to be changed after
+                // the first time it is set, so we don't have to worry about un-muting.
+                setMasterMute_l(true);
+            }
+        }
+    }
+}
+
 bool AudioFlinger::MixerThread::threadLoop()
 {
     Vector< sp<Track> > tracksToRemove;
@@ -2042,14 +2059,7 @@
                     acquireWakeLock_l();
 
                     mPrevMixerStatus = MIXER_IDLE;
-                    if (!mMasterMute) {
-                        char value[PROPERTY_VALUE_MAX];
-                        property_get("ro.audio.silent", value, "0");
-                        if (atoi(value)) {
-                            ALOGD("Silence is golden");
-                            setMasterMute_l(true);
-                        }
-                    }
+                    checkSilentMode_l();
 
                     standbyTime = systemTime() + mStandbyTimeInNsecs;
                     sleepTime = idleSleepTime;
@@ -2751,14 +2761,7 @@
                     ALOGV("DirectOutputThread %p TID %d waking up in active mode", this, gettid());
                     acquireWakeLock_l();
 
-                    if (!mMasterMute) {
-                        char value[PROPERTY_VALUE_MAX];
-                        property_get("ro.audio.silent", value, "0");
-                        if (atoi(value)) {
-                            ALOGD("Silence is golden");
-                            setMasterMute_l(true);
-                        }
-                    }
+                    checkSilentMode_l();
 
                     standbyTime = systemTime() + standbyDelay;
                     sleepTime = idleSleepTime;
@@ -3147,15 +3150,7 @@
                     ALOGV("DuplicatingThread %p TID %d waking up", this, gettid());
                     acquireWakeLock_l();
 
-                    mPrevMixerStatus = MIXER_IDLE;
-                    if (!mMasterMute) {
-                        char value[PROPERTY_VALUE_MAX];
-                        property_get("ro.audio.silent", value, "0");
-                        if (atoi(value)) {
-                            ALOGD("Silence is golden");
-                            setMasterMute_l(true);
-                        }
-                    }
+                    checkSilentMode_l();
 
                     standbyTime = systemTime() + mStandbyTimeInNsecs;
                     sleepTime = idleSleepTime;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index a2ab680..2a5d805 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -859,6 +859,9 @@
         virtual uint32_t        idleSleepTimeUs() = 0;
         virtual uint32_t        suspendSleepTimeUs() = 0;
 
+        // Code snippets that are temporarily lifted up out of threadLoop() until the merge
+                    void        checkSilentMode_l();
+
     private:
 
         friend class AudioFlinger;
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 86669f8..c705646 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -786,7 +786,7 @@
         return flags;
     }
 
-    InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
+    InputBindResult attachNewInputLocked(boolean initial) {
         if (!mBoundToMethod) {
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
                     MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
@@ -804,14 +804,11 @@
             if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
             showCurrentInputLocked(getAppShowFlags(), null);
         }
-        return needResult
-                ? new InputBindResult(session.session, mCurId, mCurSeq)
-                : null;
+        return new InputBindResult(session.session, mCurId, mCurSeq);
     }
 
     InputBindResult startInputLocked(IInputMethodClient client,
-            IInputContext inputContext, EditorInfo attribute,
-            boolean initial, boolean needResult) {
+            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
         // If no method is currently selected, do nothing.
         if (mCurMethodId == null) {
             return mNoBinding;
@@ -837,6 +834,16 @@
         } catch (RemoteException e) {
         }
 
+        return startInputUncheckedLocked(cs, inputContext, attribute, controlFlags);
+    }
+
+    InputBindResult startInputUncheckedLocked(ClientState cs,
+            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
+        // If no method is currently selected, do nothing.
+        if (mCurMethodId == null) {
+            return mNoBinding;
+        }
+
         if (mCurClient != cs) {
             // If the client is changing, we need to switch over to the new
             // one.
@@ -867,7 +874,8 @@
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
-                return attachNewInputLocked(initial, needResult);
+                return attachNewInputLocked(
+                        (controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);
             }
             if (mHaveConnection) {
                 if (mCurMethod != null) {
@@ -948,13 +956,11 @@
 
     @Override
     public InputBindResult startInput(IInputMethodClient client,
-            IInputContext inputContext, EditorInfo attribute,
-            boolean initial, boolean needResult) {
+            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
         synchronized (mMethodMap) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                return startInputLocked(client, inputContext, attribute,
-                        initial, needResult);
+                return startInputLocked(client, inputContext, attribute, controlFlags);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -997,7 +1003,7 @@
                     mCurClient.curSession = new SessionState(mCurClient,
                             method, session);
                     mCurClient.sessionRequested = false;
-                    InputBindResult res = attachNewInputLocked(true, true);
+                    InputBindResult res = attachNewInputLocked(true);
                     if (res.method != null) {
                         executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
                                 MSG_BIND_METHOD, mCurClient.client, res));
@@ -1482,36 +1488,45 @@
     }
 
     @Override
-    public void windowGainedFocus(IInputMethodClient client, IBinder windowToken,
-            boolean viewHasFocus, boolean isTextEditor, int softInputMode,
-            boolean first, int windowFlags) {
+    public InputBindResult windowGainedFocus(IInputMethodClient client, IBinder windowToken,
+            int controlFlags, int softInputMode, int windowFlags,
+            EditorInfo attribute, IInputContext inputContext) {
+        InputBindResult res = null;
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mMethodMap) {
                 if (DEBUG) Slog.v(TAG, "windowGainedFocus: " + client.asBinder()
-                        + " viewHasFocus=" + viewHasFocus
-                        + " isTextEditor=" + isTextEditor
+                        + " controlFlags=#" + Integer.toHexString(controlFlags)
                         + " softInputMode=#" + Integer.toHexString(softInputMode)
-                        + " first=" + first + " flags=#"
-                        + Integer.toHexString(windowFlags));
+                        + " windowFlags=#" + Integer.toHexString(windowFlags));
 
-                if (mCurClient == null || client == null
-                        || mCurClient.client.asBinder() != client.asBinder()) {
-                    try {
-                        // We need to check if this is the current client with
-                        // focus in the window manager, to allow this call to
-                        // be made before input is started in it.
-                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
-                            Slog.w(TAG, "Client not active, ignoring focus gain of: " + client);
-                            return;
-                        }
-                    } catch (RemoteException e) {
+                ClientState cs = mClients.get(client.asBinder());
+                if (cs == null) {
+                    throw new IllegalArgumentException("unknown client "
+                            + client.asBinder());
+                }
+
+                try {
+                    if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
+                        // Check with the window manager to make sure this client actually
+                        // has a window with focus.  If not, reject.  This is thread safe
+                        // because if the focus changes some time before or after, the
+                        // next client receiving focus that has any interest in input will
+                        // be calling through here after that change happens.
+                        Slog.w(TAG, "Focus gain on non-focused client " + cs.client
+                                + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+                        return null;
                     }
+                } catch (RemoteException e) {
                 }
 
                 if (mCurFocusedWindow == windowToken) {
                     Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
-                    return;
+                    if (attribute != null) {
+                        return startInputUncheckedLocked(cs, inputContext, attribute,
+                                controlFlags);
+                    }
+                    return null;
                 }
                 mCurFocusedWindow = windowToken;
 
@@ -1527,6 +1542,14 @@
                                 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
                         || mRes.getConfiguration().isLayoutSizeAtLeast(
                                 Configuration.SCREENLAYOUT_SIZE_LARGE);
+                final boolean isTextEditor =
+                        (controlFlags&InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR) != 0;
+
+                // We want to start input before showing the IME, but after closing
+                // it.  We want to do this after closing it to help the IME disappear
+                // more quickly (not get stuck behind it initializing itself for the
+                // new focused input, even if its window wants to hide the IME).
+                boolean didStart = false;
                         
                 switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
                     case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
@@ -1542,12 +1565,17 @@
                                 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                             // There is a focus view, and we are navigating forward
                             // into the window, so show the input window for the user.
-                            // We only do this automatically if the window an resize
-                            // to accomodate the IME (so what the user sees will give
+                            // We only do this automatically if the window can resize
+                            // to accommodate the IME (so what the user sees will give
                             // them good context without input information being obscured
                             // by the IME) or if running on a large screen where there
                             // is more room for the target window + IME.
                             if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
+                            if (attribute != null) {
+                                res = startInputUncheckedLocked(cs, inputContext, attribute,
+                                        controlFlags);
+                                didStart = true;
+                            }
                             showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                         }
                         break;
@@ -1569,18 +1597,35 @@
                         if ((softInputMode &
                                 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                             if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
+                            if (attribute != null) {
+                                res = startInputUncheckedLocked(cs, inputContext, attribute,
+                                        controlFlags);
+                                didStart = true;
+                            }
                             showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                         }
                         break;
                     case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
                         if (DEBUG) Slog.v(TAG, "Window asks to always show input");
+                        if (attribute != null) {
+                            res = startInputUncheckedLocked(cs, inputContext, attribute,
+                                    controlFlags);
+                            didStart = true;
+                        }
                         showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                         break;
                 }
+
+                if (!didStart && attribute != null) {
+                    res = startInputUncheckedLocked(cs, inputContext, attribute,
+                            controlFlags);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
+
+        return res;
     }
 
     @Override
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7169015..e471a3f 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1127,7 +1127,10 @@
                     + "; regranting permissions for internal storage");
             mSettings.mInternalSdkPlatform = mSdkVersion;
             
-            updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);
+            updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
+                    | (regrantPermissions
+                            ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
+                            : 0));
 
             // can downgrade to reader
             mSettings.writeLPr();
@@ -1473,7 +1476,7 @@
     PackageInfo generatePackageInfo(PackageParser.Package p, int flags) {
         if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
             // The package has been uninstalled but has retained data and resources.
-            return PackageParser.generatePackageInfo(p, null, flags, 0, 0);
+            return PackageParser.generatePackageInfo(p, null, flags, 0, 0, null);
         }
         final PackageSetting ps = (PackageSetting)p.mExtras;
         if (ps == null) {
@@ -1481,7 +1484,7 @@
         }
         final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
         return PackageParser.generatePackageInfo(p, gp.gids, flags,
-                ps.firstInstallTime, ps.lastUpdateTime);
+                ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions);
     }
 
     public PackageInfo getPackageInfo(String packageName, int flags) {
@@ -1934,6 +1937,7 @@
         BasePermission bp = mSettings.mPermissions.get(info.name);
         boolean added = bp == null;
         boolean changed = true;
+        int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
         if (added) {
             bp = new BasePermission(info.name, tree.sourcePackage,
                     BasePermission.TYPE_DYNAMIC);
@@ -1942,16 +1946,17 @@
                     "Not allowed to modify non-dynamic permission "
                     + info.name);
         } else {
-            if (bp.protectionLevel == info.protectionLevel
+            if (bp.protectionLevel == fixedLevel
                     && bp.perm.owner.equals(tree.perm.owner)
                     && bp.uid == tree.uid
                     && comparePermissionInfos(bp.perm.info, info)) {
                 changed = false;
             }
         }
-        bp.protectionLevel = info.protectionLevel;
-        bp.perm = new PackageParser.Permission(tree.perm.owner,
-                new PermissionInfo(info));
+        bp.protectionLevel = fixedLevel;
+        info = new PermissionInfo(info);
+        info.protectionLevel = fixedLevel;
+        bp.perm = new PackageParser.Permission(tree.perm.owner, info);
         bp.perm.info.packageName = tree.perm.info.packageName;
         bp.uid = tree.uid;
         if (added) {
@@ -1995,6 +2000,77 @@
         }
     }
 
+    public void grantPermission(String packageName, String permissionName) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
+        synchronized (mPackages) {
+            final PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            final BasePermission bp = mSettings.mPermissions.get(permissionName);
+            if (bp == null) {
+                throw new IllegalArgumentException("Unknown permission: " + packageName);
+            }
+            if (!pkg.requestedPermissions.contains(permissionName)) {
+                throw new SecurityException("Package " + packageName
+                        + " has not requested permission " + permissionName);
+            }
+            if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) == 0) {
+                throw new SecurityException("Permission " + permissionName
+                        + " is not a development permission");
+            }
+            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            if (ps == null) {
+                return;
+            }
+            final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+            if (gp.grantedPermissions.add(permissionName)) {
+                if (ps.haveGids) {
+                    gp.gids = appendInts(gp.gids, bp.gids);
+                }
+                mSettings.writeLPr();
+            }
+        }
+    }
+
+    public void revokePermission(String packageName, String permissionName) {
+        synchronized (mPackages) {
+            final PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (pkg.applicationInfo.uid != Binder.getCallingUid()) {
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
+            }
+            final BasePermission bp = mSettings.mPermissions.get(permissionName);
+            if (bp == null) {
+                throw new IllegalArgumentException("Unknown permission: " + packageName);
+            }
+            if (!pkg.requestedPermissions.contains(permissionName)) {
+                throw new SecurityException("Package " + packageName
+                        + " has not requested permission " + permissionName);
+            }
+            if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) == 0) {
+                throw new SecurityException("Permission " + permissionName
+                        + " is not a development permission");
+            }
+            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            if (ps == null) {
+                return;
+            }
+            final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+            if (gp.grantedPermissions.remove(permissionName)) {
+                gp.grantedPermissions.remove(permissionName);
+                if (ps.haveGids) {
+                    gp.gids = removeInts(gp.gids, bp.gids);
+                }
+                mSettings.writeLPr();
+            }
+        }
+    }
+
     public boolean isProtectedBroadcast(String actionName) {
         synchronized (mPackages) {
             return mProtectedBroadcasts.contains(actionName);
@@ -4117,10 +4193,13 @@
         }
         return false;
     }
-    
+
+    static final int UPDATE_PERMISSIONS_ALL = 1<<0;
+    static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1;
+    static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2;
+
     private void updatePermissionsLPw(String changingPkg,
-            PackageParser.Package pkgInfo, boolean grantPermissions,
-            boolean replace, boolean replaceAll) {
+            PackageParser.Package pkgInfo, int flags) {
         // Make sure there are no dangling permission trees.
         Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
         while (it.hasNext()) {
@@ -4138,7 +4217,7 @@
                 if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
                     Slog.i(TAG, "Removing old permission tree: " + bp.name
                             + " from package " + bp.sourcePackage);
-                    grantPermissions = true;
+                    flags |= UPDATE_PERMISSIONS_ALL;
                     it.remove();
                 }
             }
@@ -4178,7 +4257,7 @@
                 if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
                     Slog.i(TAG, "Removing old permission: " + bp.name
                             + " from package " + bp.sourcePackage);
-                    grantPermissions = true;
+                    flags |= UPDATE_PERMISSIONS_ALL;
                     it.remove();
                 }
             }
@@ -4186,16 +4265,16 @@
 
         // Now update the permissions for all packages, in particular
         // replace the granted permissions of the system packages.
-        if (grantPermissions) {
+        if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
             for (PackageParser.Package pkg : mPackages.values()) {
                 if (pkg != pkgInfo) {
-                    grantPermissionsLPw(pkg, replaceAll);
+                    grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0);
                 }
             }
         }
         
         if (pkgInfo != null) {
-            grantPermissionsLPw(pkgInfo, replace);
+            grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0);
         }
     }
 
@@ -4205,11 +4284,13 @@
             return;
         }
         final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+        HashSet<String> origPermissions = gp.grantedPermissions;
         boolean changedPermission = false;
 
         if (replace) {
             ps.permissionsFixed = false;
             if (gp == ps) {
+                origPermissions = new HashSet<String>(gp.grantedPermissions);
                 gp.grantedPermissions.clear();
                 gp.gids = mGlobalGids;
             }
@@ -4222,6 +4303,7 @@
         final int N = pkg.requestedPermissions.size();
         for (int i=0; i<N; i++) {
             final String name = pkg.requestedPermissions.get(i);
+            //final boolean required = pkg.requestedPermssionsRequired.get(i);
             final BasePermission bp = mSettings.mPermissions.get(name);
             if (DEBUG_INSTALL) {
                 if (gp != ps) {
@@ -4232,23 +4314,23 @@
                 final String perm = bp.name;
                 boolean allowed;
                 boolean allowedSig = false;
-                if (bp.protectionLevel == PermissionInfo.PROTECTION_NORMAL
-                        || bp.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
+                final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+                if (level == PermissionInfo.PROTECTION_NORMAL
+                        || level == PermissionInfo.PROTECTION_DANGEROUS) {
                     allowed = true;
                 } else if (bp.packageSetting == null) {
                     // This permission is invalid; skip it.
                     allowed = false;
-                } else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
-                        || bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
+                } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
                     allowed = (compareSignatures(
                             bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
                                     == PackageManager.SIGNATURE_MATCH)
                             || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
                                     == PackageManager.SIGNATURE_MATCH);
-                    if (!allowed && bp.protectionLevel
-                            == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
+                    if (!allowed && (bp.protectionLevel
+                            & PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {
                         if (isSystemApp(pkg)) {
-                            // For updated system applications, the signatureOrSystem permission
+                            // For updated system applications, a system permission
                             // is granted only if it had been defined by the original application.
                             if (isUpdatedSystemApp(pkg)) {
                                 final PackageSetting sysPs = mSettings
@@ -4265,6 +4347,16 @@
                             }
                         }
                     }
+                    if (!allowed && (bp.protectionLevel
+                            & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+                        // For development permissions, a development permission
+                        // is granted only if it was already granted.
+                        if (origPermissions.contains(perm)) {
+                            allowed = true;
+                        } else {
+                            allowed = false;
+                        }
+                    }
                     if (allowed) {
                         allowedSig = true;
                     }
@@ -4883,7 +4975,7 @@
                             // writer
                             synchronized (mPackages) {
                                 updatePermissionsLPw(p.packageName, p,
-                                        p.permissions.size() > 0, false, false);
+                                        p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0);
                             }
                             addedPackage = p.applicationInfo.packageName;
                             addedUid = p.applicationInfo.uid;
@@ -6447,7 +6539,7 @@
                 // writer
                 synchronized (mPackages) {
                     updatePermissionsLPw(deletedPackage.packageName, deletedPackage,
-                            true, false, false);
+                            UPDATE_PERMISSIONS_ALL);
                     // can downgrade to reader
                     mSettings.writeLPr();
                 }
@@ -6591,7 +6683,8 @@
         }
         synchronized (mPackages) {
             updatePermissionsLPw(newPackage.packageName, newPackage,
-                    newPackage.permissions.size() > 0, true, false);
+                    UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
+                            ? UPDATE_PERMISSIONS_ALL : 0));
             res.name = pkgName;
             res.uid = newPackage.applicationInfo.uid;
             res.pkg = newPackage;
@@ -7019,7 +7112,7 @@
                         outInfo.removedUid = mSettings.removePackageLPw(packageName);
                     }
                     if (deletedPs != null) {
-                        updatePermissionsLPw(deletedPs.name, null, false, false, false);
+                        updatePermissionsLPw(deletedPs.name, null, 0);
                         if (deletedPs.sharedUser != null) {
                             // remove permissions associated with package
                             mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
@@ -7102,7 +7195,8 @@
         }
         // writer
         synchronized (mPackages) {
-            updatePermissionsLPw(newPkg.packageName, newPkg, true, true, false);
+            updatePermissionsLPw(newPkg.packageName, newPkg,
+                    UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
             // can downgrade to reader here
             if (writeSettings) {
                 mSettings.writeLPr();
@@ -8320,7 +8414,10 @@
 
             // Make sure group IDs have been assigned, and any permission
             // changes in other apps are accounted for
-            updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);
+            updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
+                    | (regrantPermissions
+                            ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
+                            : 0));
             // can downgrade to reader
             // Persist settings
             mSettings.writeLPr();
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index ebf954b..5da6ac9 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1398,6 +1398,7 @@
                             dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
                     bp.protectionLevel = readInt(parser, null, "protection",
                             PermissionInfo.PROTECTION_NORMAL);
+                    bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
                     if (dynamic) {
                         PermissionInfo pi = new PermissionInfo();
                         pi.packageName = sourcePackage.intern();
@@ -2244,7 +2245,8 @@
             pw.print("    uid="); pw.print(p.uid);
                     pw.print(" gids="); pw.print(PackageManagerService.arrayToString(p.gids));
                     pw.print(" type="); pw.print(p.type);
-                    pw.print(" prot="); pw.println(p.protectionLevel);
+                    pw.print(" prot=");
+                    pw.println(PermissionInfo.protectionToString(p.protectionLevel));
             if (p.packageSetting != null) {
                 pw.print("    packageSetting="); pw.println(p.packageSetting);
             }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 58680ea..351c771 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -159,6 +159,18 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public void grantPermission(String packageName, String permissionName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void revokePermission(String packageName, String permissionName) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public int checkSignatures(String pkg1, String pkg2) {
         throw new UnsupportedOperationException();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index ed78daa3..b310d93 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -568,6 +568,15 @@
         </activity>
 
         <activity
+                android:name="TextOnPathActivity"
+                android:label="_TextOnPath">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="PathsCacheActivity"
                 android:label="_PathsCache">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextOnPathActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextOnPathActivity.java
new file mode 100644
index 0000000..b798ee7
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextOnPathActivity.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class TextOnPathActivity extends Activity {
+    private Path mPath;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mPath = makePath();
+
+        final TextOnPathView view = new TextOnPathView(this);
+        setContentView(view);
+    }
+
+    private Path makePath() {
+        Path path = new Path();
+        buildPath(path);
+        return path;
+    }
+
+    private void buildPath(Path path) {
+        path.moveTo(0.0f, 0.0f);
+        path.cubicTo(0.0f, 0.0f, 100.0f, 150.0f, 100.0f, 200.0f);
+        path.cubicTo(100.0f, 200.0f, 50.0f, 300.0f, -80.0f, 200.0f);
+        path.cubicTo(-80.0f, 200.0f, 100.0f, 200.0f, 200.0f, 0.0f);
+    }
+
+    public class TextOnPathView extends View {
+        private static final String TEST_STRING = "Hello OpenGL renderer, text on path! ";
+
+        private final Paint mPaint;
+        private final String mText;
+
+        public TextOnPathView(Context c) {
+            super(c);
+
+            mPaint = new Paint();
+            mPaint.setAntiAlias(true);
+            mPaint.setColor(0xff000000);
+
+            StringBuilder builder = new StringBuilder(TEST_STRING.length() * 2);
+            for (int i = 0; i < 2; i++) {
+                builder.append(TEST_STRING);
+            }
+            mText = builder.toString();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.drawARGB(255, 255, 255, 255);
+
+            canvas.save();
+            canvas.translate(400.0f, 350.0f);
+            mPaint.setTextAlign(Paint.Align.LEFT);
+            canvas.drawTextOnPath(mText + mText, mPath, 0.0f, 0.0f, mPaint);
+            canvas.restore();
+
+            canvas.save();
+            canvas.translate(150.0f, 60.0f);
+            canvas.drawTextOnPath(mText, mPath, 0.0f, 0.0f, mPaint);
+
+            canvas.translate(250.0f, 0.0f);
+            mPaint.setTextAlign(Paint.Align.CENTER);
+            canvas.drawTextOnPath(mText, mPath, 0.0f, 0.0f, mPaint);
+
+            canvas.translate(250.0f, 0.0f);
+            mPaint.setTextAlign(Paint.Align.RIGHT);
+            canvas.drawTextOnPath(mText, mPath, 0.0f, 0.0f, mPaint);
+            canvas.restore();
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 6afdfbe..d6abbaa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -184,8 +184,8 @@
     }
 
     @Override
-    public InputBindResult startInput(IInputMethodClient arg0, IInputContext arg1, EditorInfo arg2,
-            boolean arg3, boolean arg4) throws RemoteException {
+    public InputBindResult startInput(IInputMethodClient client, IInputContext inputContext,
+            EditorInfo attribute, int controlFlags) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
@@ -209,10 +209,11 @@
     }
 
     @Override
-    public void windowGainedFocus(IInputMethodClient arg0, IBinder arg1, boolean arg2,
-            boolean arg3, int arg4, boolean arg5, int arg6) throws RemoteException {
+    public InputBindResult windowGainedFocus(IInputMethodClient client, IBinder windowToken,
+            int controlFlags, int softInputMode, int windowFlags, EditorInfo attribute,
+            IInputContext inputContext) throws RemoteException {
         // TODO Auto-generated method stub
-
+        return null;
     }
 
     @Override