Merge "AudioManager: optimize audio port listener registration" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index d951591..2d51b97 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10,10 +10,8 @@
     field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
     field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
     field public static final java.lang.String ACCESS_LOCATION_EXTRA_COMMANDS = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
-    field public static final java.lang.String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
     field public static final java.lang.String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
     field public static final java.lang.String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
-    field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
     field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
     field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
     field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
@@ -42,7 +40,6 @@
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
     field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
-    field public static final java.lang.String BRICK = "android.permission.BRICK";
     field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
     field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
     field public static final java.lang.String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
@@ -59,33 +56,25 @@
     field public static final java.lang.String CHANGE_WIFI_MULTICAST_STATE = "android.permission.CHANGE_WIFI_MULTICAST_STATE";
     field public static final java.lang.String CHANGE_WIFI_STATE = "android.permission.CHANGE_WIFI_STATE";
     field public static final java.lang.String CLEAR_APP_CACHE = "android.permission.CLEAR_APP_CACHE";
-    field public static final java.lang.String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
     field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
     field public static final java.lang.String DELETE_CACHE_FILES = "android.permission.DELETE_CACHE_FILES";
     field public static final java.lang.String DELETE_PACKAGES = "android.permission.DELETE_PACKAGES";
-    field public static final java.lang.String DEVICE_POWER = "android.permission.DEVICE_POWER";
     field public static final java.lang.String DIAGNOSTIC = "android.permission.DIAGNOSTIC";
     field public static final java.lang.String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD";
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
     field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
-    field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
-    field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
-    field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
-    field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
     field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
-    field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
     field public static final java.lang.String INTERNET = "android.permission.INTERNET";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
-    field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
     field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
@@ -120,13 +109,10 @@
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
-    field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
     field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
     field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
     field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
-    field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
-    field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
     field public static final deprecated java.lang.String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
     field public static final java.lang.String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
     field public static final java.lang.String SET_TIME = "android.permission.SET_TIME";
@@ -5846,10 +5832,12 @@
   }
 
   public static class AssistStructure.ViewNode {
+    method public float getAlpha();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
     method public java.lang.CharSequence getContentDescription();
+    method public float getElevation();
     method public android.os.Bundle getExtras();
     method public int getHeight();
     method public java.lang.String getHint();
@@ -5868,6 +5856,7 @@
     method public float getTextSize();
     method public int getTextStyle();
     method public int getTop();
+    method public android.graphics.Matrix getTransformation();
     method public int getVisibility();
     method public int getWidth();
     method public boolean isAccessibilityFocused();
@@ -30543,8 +30532,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -30553,6 +30542,7 @@
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
+    field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
@@ -36961,6 +36951,7 @@
     method public abstract android.view.ViewStructure newChild(int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
+    method public abstract void setAlpha(float);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -36969,6 +36960,7 @@
     method public abstract void setContentDescription(java.lang.CharSequence);
     method public abstract void setContextClickable(boolean);
     method public abstract void setDimens(int, int, int, int, int, int);
+    method public abstract void setElevation(float);
     method public abstract void setEnabled(boolean);
     method public abstract void setFocusable(boolean);
     method public abstract void setFocused(boolean);
@@ -36979,6 +36971,7 @@
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextStyle(float, int, int, int);
+    method public abstract void setTransformation(android.graphics.Matrix);
     method public abstract void setVisibility(int);
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 78e0a16..33c7a1b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5964,10 +5964,12 @@
   }
 
   public static class AssistStructure.ViewNode {
+    method public float getAlpha();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
     method public java.lang.CharSequence getContentDescription();
+    method public float getElevation();
     method public android.os.Bundle getExtras();
     method public int getHeight();
     method public java.lang.String getHint();
@@ -5986,6 +5988,7 @@
     method public float getTextSize();
     method public int getTextStyle();
     method public int getTop();
+    method public android.graphics.Matrix getTransformation();
     method public int getVisibility();
     method public int getWidth();
     method public boolean isAccessibilityFocused();
@@ -32766,8 +32769,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -32776,6 +32779,7 @@
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
+    field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
@@ -39242,6 +39246,7 @@
     method public abstract android.view.ViewStructure newChild(int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
+    method public abstract void setAlpha(float);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -39250,6 +39255,7 @@
     method public abstract void setContentDescription(java.lang.CharSequence);
     method public abstract void setContextClickable(boolean);
     method public abstract void setDimens(int, int, int, int, int, int);
+    method public abstract void setElevation(float);
     method public abstract void setEnabled(boolean);
     method public abstract void setFocusable(boolean);
     method public abstract void setFocused(boolean);
@@ -39260,6 +39266,7 @@
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextStyle(float, int, int, int);
+    method public abstract void setTransformation(android.graphics.Matrix);
     method public abstract void setVisibility(int);
   }
 
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 284dfd6..3429b6e 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2,6 +2,7 @@
 
 import android.app.Activity;
 import android.content.ComponentName;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Bundle;
@@ -128,24 +129,24 @@
             view.dispatchProvideStructure(builder);
         }
 
-        WindowNode(Parcel in, PooledStringReader preader) {
+        WindowNode(Parcel in, PooledStringReader preader, float[] tmpMatrix) {
             mX = in.readInt();
             mY = in.readInt();
             mWidth = in.readInt();
             mHeight = in.readInt();
             mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             mDisplayId = in.readInt();
-            mRoot = new ViewNode(in, preader);
+            mRoot = new ViewNode(in, preader, tmpMatrix);
         }
 
-        void writeToParcel(Parcel out, PooledStringWriter pwriter) {
+        int writeToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
             out.writeInt(mX);
             out.writeInt(mY);
             out.writeInt(mWidth);
             out.writeInt(mHeight);
             TextUtils.writeToParcel(mTitle, out, 0);
             out.writeInt(mDisplayId);
-            mRoot.writeToParcel(out, pwriter);
+            return mRoot.writeToParcel(out, pwriter, tmpMatrix);
         }
 
         /**
@@ -216,7 +217,7 @@
         public static final int TEXT_STYLE_UNDERLINE = 1<<2;
         public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
 
-        int mId;
+        int mId = View.NO_ID;
         String mIdPackage;
         String mIdType;
         String mIdEntry;
@@ -226,20 +227,35 @@
         int mScrollY;
         int mWidth;
         int mHeight;
+        Matrix mMatrix;
+        float mElevation;
+        float mAlpha = 1.0f;
 
         static final int FLAGS_DISABLED = 0x00000001;
         static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
         static final int FLAGS_FOCUSABLE = 0x00000010;
         static final int FLAGS_FOCUSED = 0x00000020;
-        static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x04000000;
         static final int FLAGS_SELECTED = 0x00000040;
         static final int FLAGS_ASSIST_BLOCKED = 0x00000080;
-        static final int FLAGS_ACTIVATED = 0x40000000;
         static final int FLAGS_CHECKABLE = 0x00000100;
         static final int FLAGS_CHECKED = 0x00000200;
-        static final int FLAGS_CLICKABLE = 0x00004000;
-        static final int FLAGS_LONG_CLICKABLE = 0x00200000;
-        static final int FLAGS_CONTEXT_CLICKABLE = 0x00400000;
+        static final int FLAGS_CLICKABLE = 0x00000400;
+        static final int FLAGS_LONG_CLICKABLE = 0x00000800;
+        static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x00001000;
+        static final int FLAGS_ACTIVATED = 0x00002000;
+        static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
+
+        static final int FLAGS_HAS_MATRIX = 0x40000000;
+        static final int FLAGS_HAS_ALPHA = 0x20000000;
+        static final int FLAGS_HAS_ELEVATION = 0x10000000;
+        static final int FLAGS_HAS_SCROLL = 0x08000000;
+        static final int FLAGS_HAS_LARGE_COORDS = 0x04000000;
+        static final int FLAGS_HAS_CONTENT_DESCRIPTION = 0x02000000;
+        static final int FLAGS_HAS_TEXT = 0x01000000;
+        static final int FLAGS_HAS_EXTRAS = 0x00800000;
+        static final int FLAGS_HAS_ID = 0x00400000;
+        static final int FLAGS_HAS_CHILDREN = 0x00200000;
+        static final int FLAGS_ALL_CONTROL = 0xfff00000;
 
         int mFlags;
 
@@ -254,79 +270,153 @@
         ViewNode() {
         }
 
-        ViewNode(Parcel in, PooledStringReader preader) {
-            mId = in.readInt();
-            if (mId != 0) {
-                mIdEntry = preader.readString();
-                if (mIdEntry != null) {
-                    mIdType = preader.readString();
-                    mIdPackage = preader.readString();
-                } else {
-                    mIdPackage = mIdType = null;
-                }
-            } else {
-                mIdPackage = mIdType = mIdEntry = null;
-            }
-            mX = in.readInt();
-            mY = in.readInt();
-            mScrollX = in.readInt();
-            mScrollY = in.readInt();
-            mWidth = in.readInt();
-            mHeight = in.readInt();
-            mFlags = in.readInt();
+        ViewNode(Parcel in, PooledStringReader preader, float[] tmpMatrix) {
             mClassName = preader.readString();
-            mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            if (in.readInt() != 0) {
-                mText = new ViewNodeText(in);
-            } else {
-                mText = null;
+            mFlags = in.readInt();
+            final int flags = mFlags;
+            if ((flags&FLAGS_HAS_ID) != 0) {
+                mId = in.readInt();
+                if (mId != 0) {
+                    mIdEntry = preader.readString();
+                    if (mIdEntry != null) {
+                        mIdType = preader.readString();
+                        mIdPackage = preader.readString();
+                    }
+                }
             }
-            mExtras = in.readBundle();
-            final int NCHILDREN = in.readInt();
-            if (NCHILDREN > 0) {
+            if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
+                mX = in.readInt();
+                mY = in.readInt();
+                mWidth = in.readInt();
+                mHeight = in.readInt();
+            } else {
+                int val = in.readInt();
+                mX = val&0x7fff;
+                mY = (val>>16)&0x7fff;
+                val = in.readInt();
+                mWidth = val&0x7fff;
+                mHeight = (val>>16)&0x7fff;
+            }
+            if ((flags&FLAGS_HAS_SCROLL) != 0) {
+                mScrollX = in.readInt();
+                mScrollY = in.readInt();
+            }
+            if ((flags&FLAGS_HAS_MATRIX) != 0) {
+                mMatrix = new Matrix();
+                in.readFloatArray(tmpMatrix);
+                mMatrix.setValues(tmpMatrix);
+            }
+            if ((flags&FLAGS_HAS_ELEVATION) != 0) {
+                mElevation = in.readFloat();
+            }
+            if ((flags&FLAGS_HAS_ALPHA) != 0) {
+                mAlpha = in.readFloat();
+            }
+            if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
+                mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            }
+            if ((flags&FLAGS_HAS_TEXT) != 0) {
+                mText = new ViewNodeText(in);
+            }
+            if ((flags&FLAGS_HAS_EXTRAS) != 0) {
+                mExtras = in.readBundle();
+            }
+            if ((flags&FLAGS_HAS_CHILDREN) != 0) {
+                final int NCHILDREN = in.readInt();
                 mChildren = new ViewNode[NCHILDREN];
                 for (int i=0; i<NCHILDREN; i++) {
-                    mChildren[i] = new ViewNode(in, preader);
+                    mChildren[i] = new ViewNode(in, preader, tmpMatrix);
                 }
-            } else {
-                mChildren = null;
             }
         }
 
-        void writeToParcel(Parcel out, PooledStringWriter pwriter) {
-            out.writeInt(mId);
-            if (mId != 0) {
-                pwriter.writeString(mIdEntry);
-                if (mIdEntry != null) {
-                    pwriter.writeString(mIdType);
-                    pwriter.writeString(mIdPackage);
+        int writeToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
+            int flags = mFlags & ~FLAGS_ALL_CONTROL;
+            if (mId != View.NO_ID) {
+                flags |= FLAGS_HAS_ID;
+            }
+            if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
+                    || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
+                flags |= FLAGS_HAS_LARGE_COORDS;
+            }
+            if (mScrollX != 0 || mScrollY != 0) {
+                flags |= FLAGS_HAS_SCROLL;
+            }
+            if (mMatrix != null) {
+                flags |= FLAGS_HAS_MATRIX;
+            }
+            if (mElevation != 0) {
+                flags |= FLAGS_HAS_ELEVATION;
+            }
+            if (mAlpha != 1.0f) {
+                flags |= FLAGS_HAS_ALPHA;
+            }
+            if (mContentDescription != null) {
+                flags |= FLAGS_HAS_CONTENT_DESCRIPTION;
+            }
+            if (mText != null) {
+                flags |= FLAGS_HAS_TEXT;
+            }
+            if (mExtras != null) {
+                flags |= FLAGS_HAS_EXTRAS;
+            }
+            if (mChildren != null) {
+                flags |= FLAGS_HAS_CHILDREN;
+            }
+
+            pwriter.writeString(mClassName);
+            out.writeInt(flags);
+            if ((flags&FLAGS_HAS_ID) != 0) {
+                out.writeInt(mId);
+                if (mId != 0) {
+                    pwriter.writeString(mIdEntry);
+                    if (mIdEntry != null) {
+                        pwriter.writeString(mIdType);
+                        pwriter.writeString(mIdPackage);
+                    }
                 }
             }
-            out.writeInt(mX);
-            out.writeInt(mY);
-            out.writeInt(mScrollX);
-            out.writeInt(mScrollY);
-            out.writeInt(mWidth);
-            out.writeInt(mHeight);
-            out.writeInt(mFlags);
-            pwriter.writeString(mClassName);
-            TextUtils.writeToParcel(mContentDescription, out, 0);
-            if (mText != null) {
-                out.writeInt(1);
-                mText.writeToParcel(out);
+            if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
+                out.writeInt(mX);
+                out.writeInt(mY);
+                out.writeInt(mWidth);
+                out.writeInt(mHeight);
             } else {
-                out.writeInt(0);
+                out.writeInt((mY<<16) | mX);
+                out.writeInt((mHeight<<16) | mWidth);
             }
-            out.writeBundle(mExtras);
-            if (mChildren != null) {
+            if ((flags&FLAGS_HAS_SCROLL) != 0) {
+                out.writeInt(mScrollX);
+                out.writeInt(mScrollY);
+            }
+            if ((flags&FLAGS_HAS_MATRIX) != 0) {
+                mMatrix.getValues(tmpMatrix);
+                out.writeFloatArray(tmpMatrix);
+            }
+            if ((flags&FLAGS_HAS_ELEVATION) != 0) {
+                out.writeFloat(mElevation);
+            }
+            if ((flags&FLAGS_HAS_ALPHA) != 0) {
+                out.writeFloat(mAlpha);
+            }
+            if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
+                TextUtils.writeToParcel(mContentDescription, out, 0);
+            }
+            if ((flags&FLAGS_HAS_TEXT) != 0) {
+                mText.writeToParcel(out);
+            }
+            if ((flags&FLAGS_HAS_EXTRAS) != 0) {
+                out.writeBundle(mExtras);
+            }
+            int N = 1;
+            if ((flags&FLAGS_HAS_CHILDREN) != 0) {
                 final int NCHILDREN = mChildren.length;
                 out.writeInt(NCHILDREN);
                 for (int i=0; i<NCHILDREN; i++) {
-                    mChildren[i].writeToParcel(out, pwriter);
+                    N += mChildren[i].writeToParcel(out, pwriter, tmpMatrix);
                 }
-            } else {
-                out.writeInt(0);
             }
+            return N;
         }
 
         /**
@@ -408,6 +498,33 @@
         }
 
         /**
+         * Returns the transformation that has been applied to this view, such as a translation
+         * or scaling.  The returned Matrix object is owned by ViewNode; do not modify it.
+         * Returns null if there is no transformation applied to the view.
+         */
+        public Matrix getTransformation() {
+            return mMatrix;
+        }
+
+        /**
+         * Returns the visual elevation of the view, used for shadowing and other visual
+         * characterstics, as set by {@link ViewStructure#setElevation
+         * ViewStructure.setElevation(float)}.
+         */
+        public float getElevation() {
+            return mElevation;
+        }
+
+        /**
+         * Returns the alpha transformation of the view, used to reduce the overall opacity
+         * of the view's contents, as set by {@link ViewStructure#setAlpha
+         * ViewStructure.setAlpha(float)}.
+         */
+        public float getAlpha() {
+            return mAlpha;
+        }
+
+        /**
          * Returns the visibility mode of this view, as per
          * {@link android.view.View#getVisibility() View.getVisibility()}.
          */
@@ -646,6 +763,25 @@
         }
 
         @Override
+        public void setTransformation(Matrix matrix) {
+            if (matrix == null) {
+                mNode.mMatrix = null;
+            } else {
+                mNode.mMatrix = new Matrix(matrix);
+            }
+        }
+
+        @Override
+        public void setElevation(float elevation) {
+            mNode.mElevation = elevation;
+        }
+
+        @Override
+        public void setAlpha(float alpha) {
+            mNode.mAlpha = alpha;
+        }
+
+        @Override
         public void setVisibility(int visibility) {
             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
         }
@@ -919,6 +1055,18 @@
         if (scrollX != 0 || scrollY != 0) {
             Log.i(TAG, prefix + "  Scroll: " + scrollX + "," + scrollY);
         }
+        Matrix matrix = node.getTransformation();
+        if (matrix != null) {
+            Log.i(TAG, prefix + "  Transformation: " + matrix);
+        }
+        float elevation = node.getElevation();
+        if (elevation != 0) {
+            Log.i(TAG, prefix + "  Elevation: " + elevation);
+        }
+        float alpha = node.getAlpha();
+        if (alpha != 0) {
+            Log.i(TAG, prefix + "  Alpha: " + elevation);
+        }
         CharSequence contentDescription = node.getContentDescription();
         if (contentDescription != null) {
             Log.i(TAG, prefix + "  Content description: " + contentDescription);
@@ -1010,27 +1158,33 @@
             }
             if (mPendingAsyncChildren.size() > 0) {
                 // We waited too long, assume none of the assist structure is valid.
+                Log.w(TAG, "Skipping assist structure, waiting too long for async children (have "
+                        + mPendingAsyncChildren.size() + " remaining");
                 skipStructure = true;
             }
         }
         int start = out.dataPosition();
         PooledStringWriter pwriter = new PooledStringWriter(out);
+        float[] tmpMatrix = new float[9];
         ComponentName.writeToParcel(mActivityComponent, out);
         final int N = skipStructure ? 0 : mWindowNodes.size();
         out.writeInt(N);
+        int NV = 0;
         for (int i=0; i<N; i++) {
-            mWindowNodes.get(i).writeToParcel(out, pwriter);
+            NV += mWindowNodes.get(i).writeToParcel(out, pwriter, tmpMatrix);
         }
         pwriter.finish();
-        Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
+        Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes, containing "
+                + N + " windows, " + NV + " views");
     }
 
     void readContentFromParcel(Parcel in) {
         PooledStringReader preader = new PooledStringReader(in);
+        float[] tmpMatrix = new float[9];
         mActivityComponent = ComponentName.readFromParcel(in);
         final int N = in.readInt();
         for (int i=0; i<N; i++) {
-            mWindowNodes.add(new WindowNode(in, preader));
+            mWindowNodes.add(new WindowNode(in, preader, tmpMatrix));
         }
         //dump();
     }
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 67d9de5..eaf20d8 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -152,7 +152,6 @@
      */
     public void stopAdvertising(final AdvertiseCallback callback) {
         synchronized (mLeAdvertisers) {
-            BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
             if (callback == null) {
                 throw new IllegalArgumentException("callback cannot be null");
             }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 5190037..83d6cb0 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1020,6 +1020,11 @@
      * <p>Note: this Intent <strong>cannot</strong> be used to call emergency
      * numbers.  Applications can <strong>dial</strong> emergency numbers using
      * {@link #ACTION_DIAL}, however.
+     *
+     * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC}
+     * and above and declares as using the {@link android.Manifest.permission#CALL_PHONE}
+     * permission which is not granted, then atempting to use this action will
+     * result in a {@link java.lang.SecurityException}.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_CALL = "android.intent.action.CALL";
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index cb68d74..c9853df 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -504,4 +504,5 @@
 
     void grantDefaultPermissions(int userId);
     void setCarrierAppPackagesProvider(in IPackagesProvider provider);
+    int getMountExternalMode(int uid);
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ae74b9a..ff7a300 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1819,7 +1819,18 @@
         }
         return false;
     }
-    
+
+    /**
+     * @return {#link ExtractEditText} if it is considered to be visible and active. Otherwise
+     * {@code null} is returned.
+     */
+    private ExtractEditText getExtractEditTextIfVisible() {
+        if (!isExtractViewShown() || !isInputViewShown()) {
+            return null;
+        }
+        return mExtractEditText;
+    }
+
     /**
      * Override this to intercept key down events before they are processed by the
      * application.  If you return true, the application will not 
@@ -1835,6 +1846,10 @@
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            final ExtractEditText eet = getExtractEditTextIfVisible();
+            if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
+                return true;
+            }
             if (handleBack(false)) {
                 event.startTracking();
                 return true;
@@ -1882,11 +1897,15 @@
      * them to perform navigation in the underlying application.
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isTracking()
-                && !event.isCanceled()) {
-            return handleBack(true);
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            final ExtractEditText eet = getExtractEditTextIfVisible();
+            if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
+                return true;
+            }
+            if (event.isTracking() && !event.isCanceled()) {
+                return handleBack(true);
+            }
         }
-        
         return doMovementKey(keyCode, event, MOVEMENT_UP);
     }
 
@@ -1952,10 +1971,10 @@
         }
         onExtractedCursorMovement(dx, dy);
     }
-    
+
     boolean doMovementKey(int keyCode, KeyEvent event, int count) {
-        final ExtractEditText eet = mExtractEditText;
-        if (isExtractViewShown() && isInputViewShown() && eet != null) {
+        final ExtractEditText eet = getExtractEditTextIfVisible();
+        if (eet != null) {
             // If we are in fullscreen mode, the cursor will move around
             // the extract edit text, but should NOT cause focus to move
             // to other fields.
@@ -2006,7 +2025,7 @@
                     return true;
             }
         }
-        
+
         return false;
     }
     
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index f9c50f3..7234e98 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -643,6 +643,10 @@
             }
             if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
                 argsForZygote.add("--mount-external-default");
+            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
+                argsForZygote.add("--mount-external-read");
+            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
+                argsForZygote.add("--mount-external-write");
             }
             argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
 
@@ -802,7 +806,12 @@
      * @hide
      */
     public static final boolean isIsolated() {
-        int uid = UserHandle.getAppId(myUid());
+        return isIsolated(myUid());
+    }
+
+    /** {@hide} */
+    public static final boolean isIsolated(int uid) {
+        uid = UserHandle.getAppId(uid);
         return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
     }
 
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index e55ae99..84a879c 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1177,6 +1177,21 @@
                     _data.recycle();
                 }
             }
+
+            @Override
+            public void remountUid(int uid) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeInt(uid);
+                    mRemote.transact(Stub.TRANSACTION_remountUid, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
         }
 
         private static final String DESCRIPTOR = "IMountService";
@@ -1292,6 +1307,8 @@
         static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
         static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
 
+        static final int TRANSACTION_remountUid = IBinder.FIRST_CALL_TRANSACTION + 61;
+
         /**
          * Cast an IBinder object into an IMountService interface, generating a
          * proxy if needed.
@@ -1845,6 +1862,13 @@
                     reply.writeNoException();
                     return true;
                 }
+                case TRANSACTION_remountUid: {
+                    data.enforceInterface(DESCRIPTOR);
+                    int uid = data.readInt();
+                    remountUid(uid);
+                    reply.writeNoException();
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -2154,4 +2178,6 @@
     public String getPrimaryStorageUuid() throws RemoteException;
     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
             throws RemoteException;
+
+    public void remountUid(int uid) throws RemoteException;
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 9b26f24..aab68e9 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -871,6 +871,15 @@
     }
 
     /** {@hide} */
+    public void remountUid(int uid) {
+        try {
+            mMountService.remountUid(uid);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
     private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
     private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
     private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 51dbdee3..e63fb04 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -283,7 +283,13 @@
      * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
      * If you don't set a ClipData, it will be copied there for you when calling
      * {@link Context#startActivity(Intent)}.
-     * @see #EXTRA_OUTPUT
+     *
+     * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC} and above
+     * and declares as using the {@link android.Manifest.permission#CAMERA} permission which
+     * is not granted, then atempting to use this action will result in a {@link
+     * java.lang.SecurityException}.
+     *
+     *  @see #EXTRA_OUTPUT
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
@@ -331,6 +337,12 @@
      * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
      * If you don't set a ClipData, it will be copied there for you when calling
      * {@link Context#startActivity(Intent)}.
+     *
+     * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC} and above
+     * and declares as using the {@link android.Manifest.permission#CAMERA} permission which
+     * is not granted, then atempting to use this action will result in a {@link
+     * java.lang.SecurityException}.
+     *
      * @see #EXTRA_OUTPUT
      * @see #EXTRA_VIDEO_QUALITY
      * @see #EXTRA_SIZE_LIMIT
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 464710b..b6fa4e4c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -714,6 +714,27 @@
             float[] lineWidths = lineBreaks.widths;
             int[] flags = lineBreaks.flags;
 
+            final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
+            final boolean ellipsisMayBeApplied = ellipsize != null
+                    && (ellipsize == TextUtils.TruncateAt.END
+                        || (mMaximumVisibleLineCount == 1
+                                && ellipsize != TextUtils.TruncateAt.MARQUEE));
+            if (remainingLineCount < breakCount && ellipsisMayBeApplied) {
+                // Treat the last line and overflowed lines as a single line.
+                breaks[remainingLineCount - 1] = breaks[breakCount - 1];
+                // Calculate width and flag.
+                float width = 0;
+                int flag = 0;
+                for (int i = remainingLineCount - 1; i < breakCount; i++) {
+                    width += lineWidths[i];
+                    flag |= flags[i] & TAB_MASK;
+                }
+                lineWidths[remainingLineCount - 1] = width;
+                flags[remainingLineCount - 1] = flag;
+
+                breakCount = remainingLineCount;
+            }
+
             // here is the offset of the starting character of the line we are currently measuring
             int here = paraStart;
 
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 47d5c79..82689b9 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -105,32 +105,45 @@
             mult = TrafficStats.PB_IN_BYTES;
             result = result / 1024;
         }
-        String value;
+        // Note we calculate the rounded long by ourselves, but still let String.format()
+        // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
+        // floating point errors.
+        final int roundFactor;
+        final String roundFormat;
         if (result < 1) {
-            value = String.format("%.2f", result);
+            roundFactor = 100;
+            roundFormat = "%.2f";
         } else if (result < 10) {
             if ((flags & FLAG_SHORTER) != 0) {
-                value = String.format("%.1f", result);
+                roundFactor = 10;
+                roundFormat = "%.1f";
             } else {
-                value = String.format("%.2f", result);
+                roundFactor = 100;
+                roundFormat = "%.2f";
             }
         } else if (result < 100) {
             if ((flags & FLAG_SHORTER) != 0) {
-                value = String.format("%.0f", result);
+                roundFactor = 1;
+                roundFormat = "%.0f";
             } else {
-                value = String.format("%.2f", result);
+                roundFactor = 100;
+                roundFormat = "%.2f";
             }
         } else {
-            value = String.format("%.0f", result);
+            roundFactor = 1;
+            roundFormat = "%.0f";
         }
+        final String roundedString = String.format(roundFormat, result);
+
+        // Note this might overflow if result >= Long.MAX_VALUE / 100, but that's like 80PB so
+        // it's okay (for now)...
+        final long roundedBytes =
+                (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
+                : (((long) Math.round(result * roundFactor)) * mult / roundFactor);
+
         final String units = res.getString(suffix);
-        final long roundedBytes;
-        if ((flags & FLAG_CALCULATE_ROUNDED) != 0) {
-            roundedBytes = (long) (Double.parseDouble(value) * mult);
-        } else {
-            roundedBytes = 0;
-        }
-        return new BytesResult(value, units, roundedBytes);
+
+        return new BytesResult(roundedString, units, roundedBytes);
     }
 
     /**
diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java
index 5dda8a7..3688cfa 100644
--- a/core/java/android/text/method/WordIterator.java
+++ b/core/java/android/text/method/WordIterator.java
@@ -147,24 +147,13 @@
      * @throws IllegalArgumentException is offset is not valid.
      */
     public int getBeginning(int offset) {
-        final int shiftedOffset = offset - mOffsetShift;
-        checkOffsetIsValid(shiftedOffset);
-
-        if (isOnLetterOrDigit(shiftedOffset)) {
-            if (mIterator.isBoundary(shiftedOffset)) {
-                return shiftedOffset + mOffsetShift;
-            } else {
-                return mIterator.preceding(shiftedOffset) + mOffsetShift;
-            }
-        } else {
-            if (isAfterLetterOrDigit(shiftedOffset)) {
-                return mIterator.preceding(shiftedOffset) + mOffsetShift;
-            }
-        }
-        return BreakIterator.DONE;
+        // TODO: Check if usage of this can be updated to getBeginning(offset, true) if
+        // so this method can be removed.
+        return getBeginning(offset, false);
     }
 
-    /** If <code>offset</code> is within a word, returns the index of the last character of that
+    /**
+     * If <code>offset</code> is within a word, returns the index of the last character of that
      * word plus one, otherwise returns BreakIterator.DONE.
      *
      * The offsets that are considered to be part of a word are the indexes of its characters,
@@ -177,11 +166,106 @@
      * @throws IllegalArgumentException is offset is not valid.
      */
     public int getEnd(int offset) {
+        // TODO: Check if usage of this can be updated to getEnd(offset, true), if
+        // so this method can be removed.
+        return getEnd(offset, false);
+    }
+
+    /**
+     * If the <code>offset</code> is within a word or on a word boundary that can only be
+     * considered the start of a word (e.g. _word where "_" is any character that would not
+     * be considered part of the word) then this returns the index of the first character of
+     * that word.
+     *
+     * If the offset is on a word boundary that can be considered the start and end of a
+     * word, e.g. AABB (where AA and BB are both words) and the offset is the boundary
+     * between AA and BB, this would return the start of the previous word, AA.
+     *
+     * Returns BreakIterator.DONE if there is no previous boundary.
+     *
+     * @throws IllegalArgumentException is offset is not valid.
+     */
+    public int getPrevWordBeginningOnTwoWordsBoundary(int offset) {
+        return getBeginning(offset, true);
+    }
+
+    /**
+     * If the <code>offset</code> is within a word or on a word boundary that can only be
+     * considered the end of a word (e.g. word_ where "_" is any character that would not
+     * be considered part of the word) then this returns the index of the last character
+     * plus one of that word.
+     *
+     * If the offset is on a word boundary that can be considered the start and end of a
+     * word, e.g. AABB (where AA and BB are both words) and the offset is the boundary
+     * between AA and BB, this would return the end of the next word, BB.
+     *
+     * Returns BreakIterator.DONE if there is no next boundary.
+     *
+     * @throws IllegalArgumentException is offset is not valid.
+     */
+    public int getNextWordEndOnTwoWordBoundary(int offset) {
+        return getEnd(offset, true);
+    }
+
+    /**
+     * If the <code>offset</code> is within a word or on a word boundary that can only be
+     * considered the start of a word (e.g. _word where "_" is any character that would not
+     * be considered part of the word) then this returns the index of the first character of
+     * that word.
+     *
+     * If the offset is on a word boundary that can be considered the start and end of a
+     * word, e.g. AABB (where AA and BB are both words) and the offset is the boundary
+     * between AA and BB, and getPrevWordBeginningOnTwoWordsBoundary is true then this would
+     * return the start of the previous word, AA. Otherwise it would return the current offset,
+     * the start of BB.
+     *
+     * Returns BreakIterator.DONE if there is no previous boundary.
+     *
+     * @throws IllegalArgumentException is offset is not valid.
+     */
+    private int getBeginning(int offset, boolean getPrevWordBeginningOnTwoWordsBoundary) {
+        final int shiftedOffset = offset - mOffsetShift;
+        checkOffsetIsValid(shiftedOffset);
+
+        if (isOnLetterOrDigit(shiftedOffset)) {
+            if (mIterator.isBoundary(shiftedOffset)
+                    && (!isAfterLetterOrDigit(shiftedOffset)
+                            || !getPrevWordBeginningOnTwoWordsBoundary)) {
+                return shiftedOffset + mOffsetShift;
+            } else {
+                return mIterator.preceding(shiftedOffset) + mOffsetShift;
+            }
+        } else {
+            if (isAfterLetterOrDigit(shiftedOffset)) {
+                return mIterator.preceding(shiftedOffset) + mOffsetShift;
+            }
+        }
+        return BreakIterator.DONE;
+    }
+
+    /**
+     * If the <code>offset</code> is within a word or on a word boundary that can only be
+     * considered the end of a word (e.g. word_ where "_" is any character that would not be
+     * considered part of the word) then this returns the index of the last character plus one
+     * of that word.
+     *
+     * If the offset is on a word boundary that can be considered the start and end of a
+     * word, e.g. AABB (where AA and BB are both words) and the offset is the boundary
+     * between AA and BB, and getNextWordEndOnTwoWordBoundary is true then this would return
+     * the end of the next word, BB. Otherwise it would return the current offset, the end
+     * of AA.
+     *
+     * Returns BreakIterator.DONE if there is no next boundary.
+     *
+     * @throws IllegalArgumentException is offset is not valid.
+     */
+    private int getEnd(int offset, boolean getNextWordEndOnTwoWordBoundary) {
         final int shiftedOffset = offset - mOffsetShift;
         checkOffsetIsValid(shiftedOffset);
 
         if (isAfterLetterOrDigit(shiftedOffset)) {
-            if (mIterator.isBoundary(shiftedOffset)) {
+            if (mIterator.isBoundary(shiftedOffset)
+                    && (!isOnLetterOrDigit(shiftedOffset) || !getNextWordEndOnTwoWordBoundary)) {
                 return shiftedOffset + mOffsetShift;
             } else {
                 return mIterator.following(shiftedOffset) + mOffsetShift;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index c61ca4e..868b262 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1046,7 +1046,7 @@
      */
     public Transition removeTarget(int targetId) {
         if (targetId > 0) {
-            mTargetIds.remove(targetId);
+            mTargetIds.remove((Integer)targetId);
         }
         return this;
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 92dae2e..b3def33 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6179,6 +6179,10 @@
             structure.setId(id, null, null, null);
         }
         structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
+        if (!hasIdentityMatrix()) {
+            structure.setTransformation(getMatrix());
+        }
+        structure.setElevation(getZ());
         structure.setVisibility(getVisibility());
         structure.setEnabled(isEnabled());
         if (isClickable()) {
@@ -6215,11 +6219,6 @@
         structure.setContentDescription(getContentDescription());
     }
 
-    /** @hide */
-    public void onProvideAssistStructure(ViewStructure structure) {
-        onProvideStructure(structure);
-    }
-
     /**
      * Called when assist structure is being retrieved from a view as part of
      * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to
@@ -6232,7 +6231,6 @@
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
         if (provider != null) {
             AccessibilityNodeInfo info = createAccessibilityNodeInfo();
-            Log.i("View", "Provider of " + this + ": children=" + info.getChildCount());
             structure.setChildCount(1);
             ViewStructure root = structure.newChild(0);
             populateVirtualStructure(root, provider, info);
@@ -6240,11 +6238,6 @@
         }
     }
 
-    /** @hide */
-    public void onProvideVirtualAssistStructure(ViewStructure structure) {
-        onProvideVirtualStructure(structure);
-    }
-
     private void populateVirtualStructure(ViewStructure structure,
             AccessibilityNodeProvider provider, AccessibilityNodeInfo info) {
         structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
@@ -6284,8 +6277,6 @@
         CharSequence cname = info.getClassName();
         structure.setClassName(cname != null ? cname.toString() : null);
         structure.setContentDescription(info.getContentDescription());
-        Log.i("View", "vassist " + cname + " @ " + rect.toShortString()
-                + " text=" + info.getText() + " cd=" + info.getContentDescription());
         if (info.getText() != null || info.getError() != null) {
             structure.setText(info.getText(), info.getTextSelectionStart(),
                     info.getTextSelectionEnd());
@@ -6310,8 +6301,8 @@
      */
     public void dispatchProvideStructure(ViewStructure structure) {
         if (!isAssistBlocked()) {
-            onProvideAssistStructure(structure);
-            onProvideVirtualAssistStructure(structure);
+            onProvideStructure(structure);
+            onProvideVirtualStructure(structure);
         } else {
             structure.setClassName(getAccessibilityClassName().toString());
             structure.setAssistBlocked(true);
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 9ab0ace..794622a 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
 
@@ -50,6 +51,28 @@
             int height);
 
     /**
+     * Set the transformation matrix associated with this view, as per
+     * {@link View#getMatrix View.getMatrix()}, or null if there is none.
+     */
+    public abstract void setTransformation(Matrix matrix);
+
+    /**
+     * Set the visual elevation (shadow) of the view, as per
+     * {@link View#getZ View.getZ()}.  Note this is <em>not</em> related
+     * to the physical Z-ordering of this view relative to its other siblings (that is how
+     * they overlap when drawing), it is only the visual representation for shadowing.
+     */
+    public abstract void setElevation(float elevation);
+
+    /**
+     * Set an alpha transformation that is applied to this view, as per
+     * {@link View#getAlpha View.getAlpha()}.  Value ranges from 0
+     * (completely transparent) to 1 (completely opaque); the default is 1, which means
+     * no transformation.
+     */
+    public abstract void setAlpha(float alpha);
+
+    /**
      * Set the visibility state of this view, as per
      * {@link View#getVisibility View.getVisibility()}.
      */
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a96bf71..8bf6992 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -6605,6 +6605,8 @@
         void addScrapView(View scrap, int position) {
             final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
             if (lp == null) {
+                // Can't recycle, skip the scrap heap.
+                getSkippedScrap().add(scrap);
                 return;
             }
 
@@ -6614,6 +6616,8 @@
             // should otherwise not be recycled.
             final int viewType = lp.viewType;
             if (!shouldRecycleViewType(viewType)) {
+                // Can't recycle, skip the scrap heap.
+                getSkippedScrap().add(scrap);
                 return;
             }
 
@@ -6633,22 +6637,19 @@
                     // If the adapter has stable IDs, we can reuse the view for
                     // the same data.
                     if (mTransientStateViewsById == null) {
-                        mTransientStateViewsById = new LongSparseArray<View>();
+                        mTransientStateViewsById = new LongSparseArray<>();
                     }
                     mTransientStateViewsById.put(lp.itemId, scrap);
                 } else if (!mDataChanged) {
                     // If the data hasn't changed, we can reuse the views at
                     // their old positions.
                     if (mTransientStateViews == null) {
-                        mTransientStateViews = new SparseArray<View>();
+                        mTransientStateViews = new SparseArray<>();
                     }
                     mTransientStateViews.put(position, scrap);
                 } else {
                     // Otherwise, we'll have to remove the view and start over.
-                    if (mSkippedScrap == null) {
-                        mSkippedScrap = new ArrayList<View>();
-                    }
-                    mSkippedScrap.add(scrap);
+                    getSkippedScrap().add(scrap);
                 }
             } else {
                 if (mViewTypeCount == 1) {
@@ -6663,6 +6664,13 @@
             }
         }
 
+        private ArrayList<View> getSkippedScrap() {
+            if (mSkippedScrap == null) {
+                mSkippedScrap = new ArrayList<>();
+            }
+            return mSkippedScrap;
+        }
+
         /**
          * Finish the removal of any views that skipped the scrap heap.
          */
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 48e69a1..c96d39b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -123,6 +123,7 @@
     private static final float[] TEMP_POSITION = new float[2];
     private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
     private static final float LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS = 0.5f;
+    private static final int UNSET_X_VALUE = -1;
     // Tag used when the Editor maintains its own separate UndoManager.
     private static final String UNDO_OWNER_TAG = "Editor";
 
@@ -735,7 +736,7 @@
             retOffset = getWordIteratorWithText().getPunctuationBeginning(offset);
         } else {
             // Not on a punctuation boundary, find the word start.
-            retOffset = getWordIteratorWithText().getBeginning(offset);
+            retOffset = getWordIteratorWithText().getPrevWordBeginningOnTwoWordsBoundary(offset);
         }
         if (retOffset == BreakIterator.DONE) {
             return offset;
@@ -750,7 +751,7 @@
             retOffset = getWordIteratorWithText().getPunctuationEnd(offset);
         } else {
             // Not on a punctuation boundary, find the word end.
-            retOffset = getWordIteratorWithText().getEnd(offset);
+            retOffset = getWordIteratorWithText().getNextWordEndOnTwoWordBoundary(offset);
         }
         if (retOffset == BreakIterator.DONE) {
             return offset;
@@ -4067,6 +4068,10 @@
         private boolean mInWord = false;
         // Difference between touch position and word boundary position.
         private float mTouchWordDelta;
+        // X value of the previous updatePosition call.
+        private float mPrevX;
+        // Indicates if the handle has moved a boundary between LTR and RTL text.
+        private boolean mLanguageDirectionChanged = false;
 
         public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(drawableLtr, drawableRtl);
@@ -4127,12 +4132,48 @@
             int end = getWordEnd(offset);
             int start = getWordStart(offset);
 
-            if (offset < mPreviousOffset) {
+            if (mPrevX == UNSET_X_VALUE) {
+                mPrevX = x;
+            }
+
+            final int selectionStart = mTextView.getSelectionStart();
+            final boolean selectionStartRtl = layout.isRtlCharAt(selectionStart);
+            final boolean atRtl = layout.isRtlCharAt(offset);
+            final boolean isLvlBoundary = layout.isLevelBoundary(offset);
+            boolean isExpanding;
+
+            // We can't determine if the user is expanding or shrinking the selection if they're
+            // on a bi-di boundary, so until they've moved past the boundary we'll just place
+            // the cursor at the current position.
+            if (isLvlBoundary || (selectionStartRtl && !atRtl) || (!selectionStartRtl && atRtl)) {
+                // We're on a boundary or this is the first direction change -- just update
+                // to the current position.
+                mLanguageDirectionChanged = true;
+                mTouchWordDelta = 0.0f;
+                positionAtCursorOffset(offset, false);
+                return;
+            } else if (mLanguageDirectionChanged && !isLvlBoundary) {
+                // We've just moved past the boundary so update the position. After this we can
+                // figure out if the user is expanding or shrinking to go by word or character.
+                positionAtCursorOffset(offset, false);
+                mTouchWordDelta = 0.0f;
+                mLanguageDirectionChanged = false;
+                return;
+            } else {
+                final float xDiff = x - mPrevX;
+                if (atRtl) {
+                    isExpanding = xDiff > 0 || currLine > mPrevLine;
+                } else {
+                    isExpanding = xDiff < 0 || currLine < mPrevLine;
+                }
+            }
+
+            if (isExpanding) {
                 // User is increasing the selection.
                 if (!mInWord || currLine < mPrevLine) {
                     // We're not in a word, or we're on a different line so we'll expand by
                     // word. First ensure the user has at least entered the next word.
-                    int offsetToWord = Math.min((end - start) / 2, 2);
+                    int offsetToWord = (end - start) / 2;
                     if (offset <= end - offsetToWord || currLine < mPrevLine) {
                         offset = start;
                     } else {
@@ -4182,6 +4223,7 @@
                 }
                 positionAtCursorOffset(offset, false);
             }
+            mPrevX = x;
         }
 
         @Override
@@ -4196,6 +4238,7 @@
             if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                 // Reset the touch word offset when the user has lifted their finger.
                 mTouchWordDelta = 0.0f;
+                mPrevX = UNSET_X_VALUE;
             }
             return superResult;
         }
@@ -4206,6 +4249,10 @@
         private boolean mInWord = false;
         // Difference between touch position and word boundary position.
         private float mTouchWordDelta;
+        // X value of the previous updatePosition call.
+        private float mPrevX;
+        // Indicates if the handle has moved a boundary between LTR and RTL text.
+        private boolean mLanguageDirectionChanged = false;
 
         public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(drawableLtr, drawableRtl);
@@ -4266,12 +4313,48 @@
             int end = getWordEnd(offset);
             int start = getWordStart(offset);
 
-            if (offset > mPreviousOffset) {
+            if (mPrevX == UNSET_X_VALUE) {
+                mPrevX = x;
+            }
+
+            final int selectionEnd = mTextView.getSelectionEnd();
+            final boolean selectionEndRtl = layout.isRtlCharAt(selectionEnd);
+            final boolean atRtl = layout.isRtlCharAt(offset);
+            final boolean isLvlBoundary = layout.isLevelBoundary(offset);
+            boolean isExpanding;
+
+            // We can't determine if the user is expanding or shrinking the selection if they're
+            // on a bi-di boundary, so until they've moved past the boundary we'll just place
+            // the cursor at the current position.
+            if (isLvlBoundary || (selectionEndRtl && !atRtl) || (!selectionEndRtl && atRtl)) {
+                // We're on a boundary or this is the first direction change -- just update
+                // to the current position.
+                mLanguageDirectionChanged = true;
+                mTouchWordDelta = 0.0f;
+                positionAtCursorOffset(offset, false);
+                return;
+            } else if (mLanguageDirectionChanged && !isLvlBoundary) {
+                // We've just moved past the boundary so update the position. After this we can
+                // figure out if the user is expanding or shrinking to go by word or character.
+                positionAtCursorOffset(offset, false);
+                mTouchWordDelta = 0.0f;
+                mLanguageDirectionChanged = false;
+                return;
+            } else {
+                final float xDiff = x - mPrevX;
+                if (atRtl) {
+                    isExpanding = xDiff < 0 || currLine < mPrevLine;
+                } else {
+                    isExpanding = xDiff > 0 || currLine > mPrevLine;
+                }
+            }
+
+            if (isExpanding) {
                 // User is increasing the selection.
                 if (!mInWord || currLine > mPrevLine) {
                     // We're not in a word, or we're on a different line so we'll expand by
                     // word. First ensure the user has at least entered the next word.
-                    int midPoint = Math.min((end - start) / 2, 2);
+                    int midPoint = (end - start) / 2;
                     if (offset >= start + midPoint || currLine > mPrevLine) {
                         offset = end;
                     } else {
@@ -4321,6 +4404,7 @@
                 }
                 positionAtCursorOffset(offset, false);
             }
+            mPrevX = x;
         }
 
         @Override
@@ -4335,6 +4419,7 @@
             if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                 // Reset the touch word offset when the user has lifted their finger.
                 mTouchWordDelta = 0.0f;
+                mPrevX = UNSET_X_VALUE;
             }
             return superResult;
         }
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 3ee273c..c40289e 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -660,10 +660,11 @@
             maxWidth = containerWidth - adjacent.getRight();
         }
 
+        final int adjMaxHeight = Math.max(0, container.height());
         final int adjMaxWidth = Math.max(0, maxWidth - marginLeft - marginRight);
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
-        final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(),
-                MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
+                adjMaxHeight, MeasureSpec.UNSPECIFIED);
         view.measure(widthMeasureSpec, heightMeasureSpec);
 
         // Align to the left or right.
@@ -700,10 +701,11 @@
 
         final Rect container = mContainerRect;
         final int containerWidth = container.width();
-        final int adjMaxWidth = containerWidth - marginLeft - marginRight;
+        final int adjMaxHeight = Math.max(0, container.height());
+        final int adjMaxWidth = Math.max(0, containerWidth - marginLeft - marginRight);
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
-        final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(),
-                MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
+                adjMaxHeight, MeasureSpec.UNSPECIFIED);
         preview.measure(widthMeasureSpec, heightMeasureSpec);
 
         // Align at the vertical center, 10% from the top.
@@ -766,10 +768,11 @@
         final View track = mTrackImage;
         final View thumb = mThumbImage;
         final Rect container = mContainerRect;
-        final int maxWidth = container.width();
+        final int maxWidth = Math.max(0, container.width());
+        final int maxHeight = Math.max(0, container.height());
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
-        final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(),
-                MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
+                maxHeight, MeasureSpec.UNSPECIFIED);
         track.measure(widthMeasureSpec, heightMeasureSpec);
 
         final int top;
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 7ca450a..280ff15 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -230,28 +230,29 @@
         if (count > 1) {
             for (int i = 0; i < count; i++) {
                 final View child = mMatchParentChildren.get(i);
-
                 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
-                int childWidthMeasureSpec;
-                int childHeightMeasureSpec;
-                
+
+                final int childWidthMeasureSpec;
                 if (lp.width == LayoutParams.MATCH_PARENT) {
-                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -
-                            getPaddingLeftWithForeground() - getPaddingRightWithForeground() -
-                            lp.leftMargin - lp.rightMargin,
-                            MeasureSpec.EXACTLY);
+                    final int width = Math.max(0, getMeasuredWidth()
+                            - getPaddingLeftWithForeground() - getPaddingRightWithForeground()
+                            - lp.leftMargin - lp.rightMargin);
+                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            width, MeasureSpec.EXACTLY);
                 } else {
                     childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                             getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
                             lp.leftMargin + lp.rightMargin,
                             lp.width);
                 }
-                
+
+                final int childHeightMeasureSpec;
                 if (lp.height == LayoutParams.MATCH_PARENT) {
-                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -
-                            getPaddingTopWithForeground() - getPaddingBottomWithForeground() -
-                            lp.topMargin - lp.bottomMargin,
-                            MeasureSpec.EXACTLY);
+                    final int height = Math.max(0, getMeasuredHeight()
+                            - getPaddingTopWithForeground() - getPaddingBottomWithForeground()
+                            - lp.topMargin - lp.bottomMargin);
+                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            height, MeasureSpec.EXACTLY);
                 } else {
                     childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
                             getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 056323db..4dcc242 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -359,7 +359,7 @@
         }
 
         if (hasDividerBeforeChildAt(count)) {
-            final View child = getVirtualChildAt(count - 1);
+            final View child = getLastNonGoneChild();
             int bottom = 0;
             if (child == null) {
                 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
@@ -371,6 +371,20 @@
         }
     }
 
+    /**
+     * Finds the last child that is not gone. The last child will be used as the reference for
+     * where the end divider should be drawn.
+     */
+    private View getLastNonGoneChild() {
+        for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
+            View child = getVirtualChildAt(i);
+            if (child != null && child.getVisibility() != GONE) {
+                return child;
+            }
+        }
+        return null;
+    }
+
     void drawDividersHorizontal(Canvas canvas) {
         final int count = getVirtualChildCount();
         final boolean isLayoutRtl = isLayoutRtl();
@@ -392,7 +406,7 @@
         }
 
         if (hasDividerBeforeChildAt(count)) {
-            final View child = getVirtualChildAt(count - 1);
+            final View child = getLastNonGoneChild();
             int position;
             if (child == null) {
                 if (isLayoutRtl) {
@@ -627,21 +641,29 @@
      * @hide Pending API consideration. Currently only used internally by the system.
      */
     protected boolean hasDividerBeforeChildAt(int childIndex) {
-        if (childIndex == 0) {
-            return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
-        } else if (childIndex == getChildCount()) {
+        if (childIndex == getVirtualChildCount()) {
+            // Check whether the end divider should draw.
             return (mShowDividers & SHOW_DIVIDER_END) != 0;
-        } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
-            boolean hasVisibleViewBefore = false;
-            for (int i = childIndex - 1; i >= 0; i--) {
-                if (getChildAt(i).getVisibility() != GONE) {
-                    hasVisibleViewBefore = true;
-                    break;
-                }
-            }
-            return hasVisibleViewBefore;
         }
-        return false;
+        boolean allViewsAreGoneBefore = allViewsAreGoneBefore(childIndex);
+        if (allViewsAreGoneBefore) {
+            // This is the first view that's not gone, check if beginning divider is enabled.
+            return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
+        } else {
+            return (mShowDividers & SHOW_DIVIDER_MIDDLE) != 0;
+        }
+    }
+
+    /**
+     * Checks whether all (virtual) child views before the given index are gone.
+     */
+    private boolean allViewsAreGoneBefore(int childIndex) {
+        for (int i = childIndex - 1; i >= 0; i--) {
+            if (getVirtualChildAt(i).getVisibility() != GONE) {
+                return false;
+            }
+        }
+        return true;
     }
 
     /**
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 534bfad..c6de5dd 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1127,10 +1127,19 @@
                     break;
                 }
 
-                // measure the hint's height to find how much more vertical space
-                // we need to add to the drop down's height
-                int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
-                int heightSpec = MeasureSpec.UNSPECIFIED;
+                // Measure the hint's height to find how much more vertical
+                // space we need to add to the drop down's height.
+                final int widthSize;
+                final int widthMode;
+                if (mDropDownWidth >= 0) {
+                    widthMode = MeasureSpec.AT_MOST;
+                    widthSize = mDropDownWidth;
+                } else {
+                    widthMode = MeasureSpec.UNSPECIFIED;
+                    widthSize = 0;
+                }
+                final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+                final int heightSpec = MeasureSpec.UNSPECIFIED;
                 hintView.measure(widthSpec, heightSpec);
 
                 hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 49226cd0..f45e750 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -242,6 +242,38 @@
                 com.android.internal.R.styleable.Switch_switchPadding, 0);
         mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
 
+        ColorStateList thumbTintList = a.getColorStateList(
+                com.android.internal.R.styleable.Switch_thumbTint);
+        if (thumbTintList != null) {
+            mThumbTintList = thumbTintList;
+            mHasThumbTint = true;
+        }
+        PorterDuff.Mode thumbTintMode = Drawable.parseTintMode(
+                a.getInt(com.android.internal.R.styleable.Switch_thumbTintMode, -1), null);
+        if (mThumbTintMode != thumbTintMode) {
+            mThumbTintMode = thumbTintMode;
+            mHasThumbTintMode = true;
+        }
+        if (mHasThumbTint || mHasThumbTintMode) {
+            applyThumbTint();
+        }
+
+        ColorStateList trackTintList = a.getColorStateList(
+                com.android.internal.R.styleable.Switch_trackTint);
+        if (trackTintList != null) {
+            mTrackTintList = trackTintList;
+            mHasTrackTint = true;
+        }
+        PorterDuff.Mode trackTintMode = Drawable.parseTintMode(
+                a.getInt(com.android.internal.R.styleable.Switch_trackTintMode, -1), null);
+        if (mTrackTintMode != trackTintMode) {
+            mTrackTintMode = trackTintMode;
+            mHasTrackTintMode = true;
+        }
+        if (mHasTrackTint || mHasTrackTintMode) {
+            applyTrackTint();
+        }
+
         final int appearance = a.getResourceId(
                 com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
         if (appearance != 0) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 207605e..310b474 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5231,7 +5231,7 @@
         // ExtractEditText does not call onFocus when it is displayed, and mHasSelectionOnFocus can
         // not be set. Do the test here instead.
         if (isInExtractedMode() && hasSelection() && mEditor != null
-                && mEditor.mTextActionMode == null) {
+                && mEditor.mTextActionMode == null && isShown() && hasWindowFocus()) {
             mEditor.startSelectionActionMode();
         }
 
@@ -5849,31 +5849,43 @@
 
     @Override
     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            boolean isInSelectionMode = mEditor != null && mEditor.mTextActionMode != null;
-
-            if (isInSelectionMode) {
-                if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
-                    KeyEvent.DispatcherState state = getKeyDispatcherState();
-                    if (state != null) {
-                        state.startTracking(event, this);
-                    }
-                    return true;
-                } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                    KeyEvent.DispatcherState state = getKeyDispatcherState();
-                    if (state != null) {
-                        state.handleUpEvent(event);
-                    }
-                    if (event.isTracking() && !event.isCanceled()) {
-                        stopTextActionMode();
-                        return true;
-                    }
-                }
-            }
+        // Note: If the IME is in fullscreen mode and IMS#mExtractEditText is in text action mode,
+        // InputMethodService#onKeyDown and InputMethodService#onKeyUp are responsible to call
+        // InputMethodService#mExtractEditText.maybeHandleBackInTextActionMode(event).
+        if (keyCode == KeyEvent.KEYCODE_BACK && handleBackInTextActionModeIfNeeded(event)) {
+            return true;
         }
         return super.onKeyPreIme(keyCode, event);
     }
 
+    /**
+     * @hide
+     */
+    public boolean handleBackInTextActionModeIfNeeded(KeyEvent event) {
+        // Do nothing unless mEditor is in text action mode.
+        if (mEditor == null || mEditor.mTextActionMode == null) {
+            return false;
+        }
+
+        if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+            KeyEvent.DispatcherState state = getKeyDispatcherState();
+            if (state != null) {
+                state.startTracking(event, this);
+            }
+            return true;
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            KeyEvent.DispatcherState state = getKeyDispatcherState();
+            if (state != null) {
+                state.handleUpEvent(event);
+            }
+            if (event.isTracking() && !event.isCanceled()) {
+                stopTextActionMode();
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         int which = doKeyDown(keyCode, event, null);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index c97fdf4..197004c 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -46,8 +46,12 @@
 
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = 0;
-    /** Default user-specific external storage should be mounted. */
+    /** Default external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_DEFAULT = 1;
+    /** Read-only external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_READ = 2;
+    /** Read-write external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_WRITE = 3;
 
     private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
 
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index fa870b9..3e86fac 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -519,6 +519,10 @@
                     niceName = arg.substring(arg.indexOf('=') + 1);
                 } else if (arg.equals("--mount-external-default")) {
                     mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
+                } else if (arg.equals("--mount-external-read")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_READ;
+                } else if (arg.equals("--mount-external-write")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
                 } else if (arg.equals("--query-abi-list")) {
                     abiListQuery = true;
                 } else if (arg.startsWith("--instruction-set=")) {
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 523663c..32a145c 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -23,6 +23,7 @@
 import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -30,6 +31,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.text.TextUtils;
 import android.util.Size;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -108,8 +110,10 @@
      * Initializes a floating toolbar.
      */
     public FloatingToolbar(Context context, Window window) {
-        mContext = Preconditions.checkNotNull(context);
-        mPopup = new FloatingToolbarPopup(window.getDecorView());
+        Preconditions.checkNotNull(context);
+        Preconditions.checkNotNull(window);
+        mContext = applyDefaultTheme(context);
+        mPopup = new FloatingToolbarPopup(mContext, window.getDecorView());
     }
 
     /**
@@ -276,6 +280,7 @@
         public static final int OVERFLOW_DIRECTION_UP = 0;
         public static final int OVERFLOW_DIRECTION_DOWN = 1;
 
+        private final Context mContext;
         private final View mParent;
         private final PopupWindow mPopupWindow;
         private final ViewGroup mContentContainer;
@@ -375,9 +380,10 @@
          * @param parent  A parent view to get the {@link android.view.View#getWindowToken()} token
          *      from.
          */
-        public FloatingToolbarPopup(View parent) {
+        public FloatingToolbarPopup(Context context, View parent) {
             mParent = Preconditions.checkNotNull(parent);
-            mContentContainer = createContentContainer(parent.getContext());
+            mContext = Preconditions.checkNotNull(context);
+            mContentContainer = createContentContainer(context);
             mPopupWindow = createPopupWindow(mContentContainer);
             mDismissAnimation = createExitAnimation(
                     mContentContainer,
@@ -415,7 +421,7 @@
 
             mContentContainer.removeAllViews();
             if (mMainPanel == null) {
-                mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow);
+                mMainPanel = new FloatingToolbarMainPanel(mContext, mOpenOverflow);
             }
             List<MenuItem> overflowMenuItems =
                     mMainPanel.layoutMenuItems(menuItems, getToolbarWidth(suggestedWidth));
@@ -423,7 +429,7 @@
             if (!overflowMenuItems.isEmpty()) {
                 if (mOverflowPanel == null) {
                     mOverflowPanel =
-                            new FloatingToolbarOverflowPanel(mParent.getContext(), mCloseOverflow);
+                            new FloatingToolbarOverflowPanel(mContext, mCloseOverflow);
                 }
                 mOverflowPanel.setMenuItems(overflowMenuItems);
                 mOverflowPanel.setOnMenuItemClickListener(menuItemClickListener);
@@ -540,7 +546,7 @@
          * Returns the context this popup is running in.
          */
         public Context getContext() {
-            return mContentContainer.getContext();
+            return mContext;
         }
 
         private void refreshCoordinatesAndOverflowDirection(Rect contentRect) {
@@ -562,7 +568,7 @@
                 } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()) {
                     // There is enough space at the bottom of the content.
                     y = contentRect.bottom;
-                } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(getContext())) {
+                } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(mContext)) {
                     // Just enough space to fit the toolbar with no vertical margins.
                     y = contentRect.bottom - mMarginVertical;
                 } else {
@@ -621,7 +627,7 @@
         }
 
         private int getToolbarHeightWithVerticalMargin() {
-            return getEstimatedToolbarHeight(mParent.getContext()) + mMarginVertical * 2;
+            return getEstimatedToolbarHeight(mContext) + mMarginVertical * 2;
         }
 
         /**
@@ -1477,6 +1483,17 @@
         return animation;
     }
 
+    /**
+     * Returns a re-themed context with controlled look and feel for views.
+     */
+    private static Context applyDefaultTheme(Context originalContext) {
+        TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme});
+        boolean isLightTheme = a.getBoolean(0, true);
+        int themeId = isLightTheme ? R.style.Theme_Material_Light : R.style.Theme_Material;
+        a.recycle();
+        return new ContextThemeWrapper(originalContext, themeId);
+    }
+
     private static int getEstimatedToolbarHeight(Context context) {
         return context.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_height);
     }
@@ -1486,18 +1503,6 @@
                 .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width);
     }
 
-    private static int getAdjustedToolbarWidth(Context context, int width) {
-        int maximumWidth = getScreenWidth(context) - 2 * context.getResources()
-                .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
-
-        if (width <= 0 || width > maximumWidth) {
-            int defaultWidth = context.getResources()
-                    .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width);
-            width = Math.min(defaultWidth, maximumWidth);
-        }
-        return width;
-    }
-
     /**
      * Returns the device's screen width.
      */
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 70a7805..e2cfa44 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -682,18 +682,28 @@
             break;
         case FAILED_TRANSACTION: {
             ALOGE("!!! FAILED BINDER TRANSACTION !!!  (parcel size = %d)", parcelSize);
+            const char* exceptionToThrow;
             char msg[128];
-            snprintf(msg, sizeof(msg)-1, "data parcel size %d bytes", parcelSize);
             // TransactionTooLargeException is a checked exception, only throw from certain methods.
             // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
             //        but it is not the only one.  The Binder driver can return BR_FAILED_REPLY
             //        for other reasons also, such as if the transaction is malformed or
             //        refers to an FD that has been closed.  We should change the driver
             //        to enable us to distinguish these cases in the future.
-            jniThrowException(env, canThrowRemoteException
-                    ? "android/os/TransactionTooLargeException"
-                            : "java/lang/RuntimeException",
-                    parcelSize > 0 ? msg : NULL);
+            if (canThrowRemoteException && parcelSize > 200*1024) {
+                // bona fide large payload
+                exceptionToThrow = "android/os/TransactionTooLargeException";
+                snprintf(msg, sizeof(msg)-1, "data parcel size %d bytes", parcelSize);
+            } else {
+                // Heuristic: a payload smaller than this threshold "shouldn't" be too
+                // big, so it's probably some other, more subtle problem.  In practice
+                // it nearly always means that the remote process died while the binder
+                // transaction was already in flight.
+                exceptionToThrow = "java/lang/RuntimeException";
+                snprintf(msg, sizeof(msg)-1,
+                        "Transaction failed on small parcel; remote process probably died");
+            }
+            jniThrowException(env, exceptionToThrow, msg);
         } break;
         case FDS_NOT_ALLOWED:
             jniThrowException(env, "java/lang/RuntimeException",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index a526223..daa6f82 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -48,7 +48,6 @@
 #define LIB_SUFFIX_LEN (sizeof(LIB_SUFFIX) - 1)
 
 #define RS_BITCODE_SUFFIX ".bc"
-#define RS_BITCODE_SUFFIX_LEN (sizeof(RS_BITCODE_SUFFIX) -1)
 
 #define GDBSERVER "gdbserver"
 #define GDBSERVER_LEN (sizeof(GDBSERVER) - 1)
@@ -322,7 +321,8 @@
 public:
     static NativeLibrariesIterator* create(ZipFileRO* zipFile) {
         void* cookie = NULL;
-        if (!zipFile->startIteration(&cookie)) {
+        // Do not specify a suffix to find both .so files and gdbserver.
+        if (!zipFile->startIteration(&cookie, APK_LIB, NULL /* suffix */)) {
             return NULL;
         }
 
@@ -337,11 +337,6 @@
                 continue;
             }
 
-            // Make sure we're in the lib directory of the ZIP.
-            if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) {
-                continue;
-            }
-
             // Make sure the filename is at least to the minimum library name size.
             const size_t fileNameLen = strlen(fileName);
             static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
@@ -529,7 +524,7 @@
         jlong apkHandle) {
     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
     void* cookie = NULL;
-    if (!zipFile->startIteration(&cookie)) {
+    if (!zipFile->startIteration(&cookie, NULL /* prefix */, RS_BITCODE_SUFFIX)) {
         return APK_SCAN_ERROR;
     }
 
@@ -539,12 +534,9 @@
         if (zipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
             continue;
         }
-
-        const size_t fileNameLen = strlen(fileName);
         const char* lastSlash = strrchr(fileName, '/');
         const char* baseName = (lastSlash == NULL) ? fileName : fileName + 1;
-        if (!strncmp(fileName + fileNameLen - RS_BITCODE_SUFFIX_LEN, RS_BITCODE_SUFFIX,
-                     RS_BITCODE_SUFFIX_LEN) && isFilenameSafe(baseName)) {
+        if (isFilenameSafe(baseName)) {
             zipFile->endIteration(cookie);
             return BITCODE_PRESENT;
         }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 76db5d3..f7cfe0e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -66,6 +66,8 @@
 enum MountExternalKind {
   MOUNT_EXTERNAL_NONE = 0,
   MOUNT_EXTERNAL_DEFAULT = 1,
+  MOUNT_EXTERNAL_READ = 2,
+  MOUNT_EXTERNAL_WRITE = 3,
 };
 
 static void RuntimeAbort(JNIEnv* env) {
@@ -249,38 +251,49 @@
 
 // Create a private mount namespace and bind mount appropriate emulated
 // storage for the given user.
-static bool MountEmulatedStorage(uid_t uid, jint mount_mode, bool force_mount_namespace) {
-  if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
+        bool force_mount_namespace) {
+    // See storage config details at http://source.android.com/tech/storage/
+
+    // Create a second private mount namespace for our process
+    if (unshare(CLONE_NEWNS) == -1) {
+        ALOGW("Failed to unshare(): %s", strerror(errno));
+        return false;
+    }
+
+    // Unmount storage provided by root namespace and mount requested view
+    umount2("/storage", MNT_FORCE);
+
+    String8 storageSource;
+    if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
+        storageSource = "/mnt/runtime_default";
+    } else if (mount_mode == MOUNT_EXTERNAL_READ) {
+        storageSource = "/mnt/runtime_read";
+    } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
+        storageSource = "/mnt/runtime_write";
+    } else {
+        // Sane default of no storage visible
+        return true;
+    }
+    if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
+            NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+        ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
+        return false;
+    }
+
+    // Mount user-specific symlink helpers into place
+    userid_t user_id = multiuser_get_user_id(uid);
+    const String8 userSource(String8::format("/mnt/user/%d", user_id));
+    if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
+        return false;
+    }
+    if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
+            NULL, MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno));
+        return false;
+    }
+
     return true;
-  }
-
-  // Create a second private mount namespace for our process
-  if (unshare(CLONE_NEWNS) == -1) {
-      ALOGW("Failed to unshare(): %s", strerror(errno));
-      return false;
-  }
-
-  if (mount_mode == MOUNT_EXTERNAL_NONE) {
-    return true;
-  }
-
-  // See storage config details at http://source.android.com/tech/storage/
-  userid_t user_id = multiuser_get_user_id(uid);
-
-  // Bind mount user-specific storage into place
-  const String8 source(String8::format("/mnt/user/%d", user_id));
-  const String8 target(String8::format("/storage/self"));
-
-  if (fs_prepare_dir(source.string(), 0755, 0, 0) == -1) {
-    return false;
-  }
-
-  if (TEMP_FAILURE_RETRY(mount(source.string(), target.string(), NULL, MS_BIND, NULL)) == -1) {
-    ALOGW("Failed to mount %s to %s: %s", source.string(), target.string(), strerror(errno));
-    return false;
-  }
-
-  return true;
 }
 
 static bool NeedsNoRandomizeWorkaround() {
@@ -543,7 +556,7 @@
   pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                       debug_flags, rlimits,
                                       permittedCapabilities, effectiveCapabilities,
-                                      MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
+                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                       NULL, NULL);
   if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9637cf5..2cbfae2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -335,14 +335,18 @@
         android:description="@string/permgroupdesc_contacts"
         android:priority="100" />
 
-    <!-- Allows an application to read the user's contacts data. -->
+    <!-- Allows an application to read the user's contacts data.
+        <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.READ_CONTACTS"
         android:permissionGroup="android.permission-group.CONTACTS"
         android:label="@string/permlab_readContacts"
         android:description="@string/permdesc_readContacts"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to write the user's contacts data. -->
+    <!-- Allows an application to write the user's contacts data.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.WRITE_CONTACTS"
         android:permissionGroup="android.permission-group.CONTACTS"
         android:label="@string/permlab_writeContacts"
@@ -361,14 +365,18 @@
         android:description="@string/permgroupdesc_calendar"
         android:priority="200" />
 
-    <!-- Allows an application to read the user's calendar data. -->
+    <!-- Allows an application to read the user's calendar data.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.READ_CALENDAR"
         android:permissionGroup="android.permission-group.CALENDAR"
         android:label="@string/permlab_readCalendar"
         android:description="@string/permdesc_readCalendar"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to write the user's calendar data. -->
+    <!-- Allows an application to write the user's calendar data.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.WRITE_CALENDAR"
         android:permissionGroup="android.permission-group.CALENDAR"
         android:label="@string/permlab_writeCalendar"
@@ -387,7 +395,9 @@
         android:description="@string/permgroupdesc_sms"
         android:priority="300" />
 
-    <!-- Allows an application to send SMS messages. -->
+    <!-- Allows an application to send SMS messages.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.SEND_SMS"
         android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_sendSms"
@@ -395,28 +405,36 @@
         android:permissionFlags="costsMoney"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to receive SMS messages. -->
+    <!-- Allows an application to receive SMS messages.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.RECEIVE_SMS"
         android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_receiveSms"
         android:description="@string/permdesc_receiveSms"
         android:protectionLevel="dangerous"/>
 
-    <!-- Allows an application to read SMS messages. -->
+    <!-- Allows an application to read SMS messages.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.READ_SMS"
         android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_readSms"
         android:description="@string/permdesc_readSms"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to receive WAP push messages. -->
+    <!-- Allows an application to receive WAP push messages.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.RECEIVE_WAP_PUSH"
         android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_receiveWapPush"
         android:description="@string/permdesc_receiveWapPush"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to monitor incoming MMS messages. -->
+    <!-- Allows an application to monitor incoming MMS messages.
+        <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.RECEIVE_MMS"
         android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_receiveMms"
@@ -433,6 +451,7 @@
          additional emergency information (if Internet access is available)
          when the alert is first received, and to delay presenting the info
          to the user until after the initial alert dialog is dismissed.
+         <p>Protection level: dangerous
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_CELL_BROADCASTS"
         android:permissionGroup="android.permission-group.SMS"
@@ -471,7 +490,9 @@
      targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
      grants your app this permission. If you don't need this permission, be sure your <a
      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-     targetSdkVersion}</a> is 4 or higher.-->
+     targetSdkVersion}</a> is 4 or higher.
+     <p>Protection level: dangerous
+     -->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardRead"
@@ -490,7 +511,9 @@
          <p>Starting in API level 19, this permission is <em>not</em> required to
          read/write files in your application-specific directories returned by
          {@link android.content.Context#getExternalFilesDir} and
-         {@link android.content.Context#getExternalCacheDir}. -->
+         {@link android.content.Context#getExternalCacheDir}.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardWrite"
@@ -509,14 +532,18 @@
         android:description="@string/permgroupdesc_location"
         android:priority="400" />
 
-    <!-- Allows an app to access precise location. -->
+    <!-- Allows an app to access precise location.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.ACCESS_FINE_LOCATION"
         android:permissionGroup="android.permission-group.LOCATION"
         android:label="@string/permlab_accessFineLocation"
         android:description="@string/permdesc_accessFineLocation"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an app to access approximate location. -->
+    <!-- Allows an app to access approximate location.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.ACCESS_COARSE_LOCATION"
         android:permissionGroup="android.permission-group.LOCATION"
         android:label="@string/permlab_accessCoarseLocation"
@@ -543,7 +570,9 @@
          targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
          grants your app this permission. If you don't need this permission, be sure your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> is 4 or higher. -->
+         targetSdkVersion}</a> is 4 or higher.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.READ_PHONE_STATE"
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_readPhoneState"
@@ -551,7 +580,9 @@
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to initiate a phone call without going through
-        the Dialer user interface for the user to confirm the call. -->
+        the Dialer user interface for the user to confirm the call.
+        <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.CALL_PHONE"
         android:permissionGroup="android.permission-group.PHONE"
         android:permissionFlags="costsMoney"
@@ -568,7 +599,9 @@
          targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
          grants your app this permission. If you don't need this permission, be sure your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> is 16 or higher.</p> -->
+         targetSdkVersion}</a> is 16 or higher.</p>
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.READ_CALL_LOG"
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_readCallLog"
@@ -585,21 +618,27 @@
          targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
          grants your app this permission. If you don't need this permission, be sure your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> is 16 or higher.</p>  -->
+         targetSdkVersion}</a> is 16 or higher.</p>
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.WRITE_CALL_LOG"
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_writeCallLog"
         android:description="@string/permdesc_writeCallLog"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to add voicemails into the system. -->
+    <!-- Allows an application to add voicemails into the system.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_addVoicemail"
         android:description="@string/permdesc_addVoicemail"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to use SIP service. -->
+    <!-- Allows an application to use SIP service.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.USE_SIP"
         android:permissionGroup="android.permission-group.PHONE"
         android:description="@string/permdesc_use_sip"
@@ -608,7 +647,9 @@
 
     <!-- Allows an application to see the number being dialed during an outgoing
          call with the option to redirect the call to a different number or
-         abort the call altogether. -->
+         abort the call altogether.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_processOutgoingCalls"
@@ -629,7 +670,9 @@
         android:description="@string/permgroupdesc_microphone"
         android:priority="600" />
 
-    <!-- Allows an application to record audio. -->
+    <!-- Allows an application to record audio.
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.RECORD_AUDIO"
         android:permissionGroup="android.permission-group.MICROPHONE"
         android:label="@string/permlab_recordAudio"
@@ -655,7 +698,9 @@
          &lt;uses-feature&gt;}</a> manifest element for <em>all</em> camera features.
          If you do not require all camera features or can properly operate if a camera
          is not available, then you must modify your manifest as appropriate in order to
-         install on devices that don't support all camera features.</p> -->
+         install on devices that don't support all camera features.</p>
+         <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.CAMERA"
         android:permissionGroup="android.permission-group.CAMERA"
         android:label="@string/permlab_camera"
@@ -676,14 +721,17 @@
         android:priority="800" />
 
     <!-- Allows an application to access data from sensors that the user uses to
-         measure what is happening inside his/her body, such as heart rate. -->
+         measure what is happening inside his/her body, such as heart rate.
+         <p>Protection level: dangerous -->
     <permission android:name="android.permission.BODY_SENSORS"
         android:permissionGroup="android.permission-group.SENSORS"
         android:label="@string/permlab_bodySensors"
         android:description="@string/permdesc_bodySensors"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an app to use fingerprint hardware. -->
+    <!-- Allows an app to use fingerprint hardware.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.USE_FINGERPRINT"
         android:permissionGroup="android.permission-group.SENSORS"
         android:label="@string/permlab_useFingerprint"
@@ -768,7 +816,9 @@
     <!-- =============================================================== -->
     <eat-comment />
 
-    <!-- Allows an application to broadcast an Intent to set an alarm for the user. -->
+    <!-- Allows an application to broadcast an Intent to set an alarm for the user.
+         <p>Protection level: normal
+    -->
     <permission android:name="com.android.alarm.permission.SET_ALARM"
         android:label="@string/permlab_setAlarm"
         android:description="@string/permdesc_setAlarm"
@@ -779,11 +829,15 @@
     <!-- =============================================================== -->
     <eat-comment />
 
-    <!-- Allows an application to modify and remove existing voicemails in the system -->
+    <!-- Allows an application to modify and remove existing voicemails in the system
+        <p>Protection level: system|signature
+    -->
     <permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"
         android:protectionLevel="system|signature" />
 
-    <!-- Allows an application to read voicemails in the system. -->
+    <!-- Allows an application to read voicemails in the system.
+         <p>Protection level: system|signature
+    -->
     <permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"
         android:protectionLevel="system|signature" />
 
@@ -792,7 +846,9 @@
     <!-- ======================================= -->
     <eat-comment />
 
-    <!-- Allows an application to access extra location provider commands -->
+    <!-- Allows an application to access extra location provider commands
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"
         android:label="@string/permlab_accessLocationExtraCommands"
         android:description="@string/permdesc_accessLocationExtraCommands"
@@ -816,7 +872,10 @@
         android:protectionLevel="signature|system" />
     <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
 
-    <!-- Allows an application to create mock location providers for testing. -->
+    <!-- @SystemApi Allows an application to create mock location providers for testing.
+         <p>Protection level: signature
+         @hide
+    -->
     <permission android:name="android.permission.ACCESS_MOCK_LOCATION"
         android:protectionLevel="signature" />
 
@@ -825,25 +884,33 @@
     <!-- ======================================= -->
     <eat-comment />
 
-    <!-- Allows applications to open network sockets. -->
+    <!-- Allows applications to open network sockets.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.INTERNET"
         android:description="@string/permdesc_createNetworkSockets"
         android:label="@string/permlab_createNetworkSockets"
         android:protectionLevel="normal" />
 
-    <!-- Allows applications to access information about networks -->
+    <!-- Allows applications to access information about networks
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.ACCESS_NETWORK_STATE"
         android:description="@string/permdesc_accessNetworkState"
         android:label="@string/permlab_accessNetworkState"
         android:protectionLevel="normal" />
 
-    <!-- Allows applications to access information about Wi-Fi networks -->
+    <!-- Allows applications to access information about Wi-Fi networks.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.ACCESS_WIFI_STATE"
         android:description="@string/permdesc_accessWifiState"
         android:label="@string/permlab_accessWifiState"
         android:protectionLevel="normal" />
 
-    <!-- Allows applications to change Wi-Fi connectivity state -->
+    <!-- Allows applications to change Wi-Fi connectivity state.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.CHANGE_WIFI_STATE"
         android:description="@string/permdesc_changeWifiState"
         android:label="@string/permlab_changeWifiState"
@@ -890,13 +957,17 @@
     <!-- ======================================= -->
     <eat-comment />
 
-    <!-- Allows applications to connect to paired bluetooth devices -->
+    <!-- Allows applications to connect to paired bluetooth devices.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.BLUETOOTH"
         android:description="@string/permdesc_bluetooth"
         android:label="@string/permlab_bluetooth"
         android:protectionLevel="normal" />
 
-    <!-- Allows applications to discover and pair bluetooth devices -->
+    <!-- Allows applications to discover and pair bluetooth devices.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.BLUETOOTH_ADMIN"
         android:description="@string/permdesc_bluetoothAdmin"
         android:label="@string/permlab_bluetoothAdmin"
@@ -920,7 +991,9 @@
     <permission android:name="android.permission.BLUETOOTH_STACK"
         android:protectionLevel="signature" />
 
-    <!-- Allows applications to perform I/O operations over NFC -->
+    <!-- Allows applications to perform I/O operations over NFC.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.NFC"
         android:description="@string/permdesc_nfc"
         android:label="@string/permlab_nfc"
@@ -960,10 +1033,12 @@
         android:permissionGroupFlags="personalInfo"
         android:priority="1000" />
 
-    <!-- Allows access to the list of accounts in the Accounts Service -->
+    <!-- Allows access to the list of accounts in the Accounts Service.
+        <p>Protection level: dangerous
+    -->
     <permission android:name="android.permission.GET_ACCOUNTS"
         android:permissionGroup="android.permission-group.CONTACTS"
-        android:protectionLevel="normal"
+        android:protectionLevel="dangerous"
         android:description="@string/permdesc_getAccounts"
         android:label="@string/permlab_getAccounts" />
 
@@ -978,32 +1053,42 @@
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Allows applications to enter Wi-Fi Multicast mode -->
+    <!-- Allows applications to enter Wi-Fi Multicast mode.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
         android:description="@string/permdesc_changeWifiMulticastState"
         android:label="@string/permlab_changeWifiMulticastState"
         android:protectionLevel="normal" />
 
-    <!-- Allows access to the vibrator -->
+    <!-- Allows access to the vibrator.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.VIBRATE"
         android:label="@string/permlab_vibrate"
         android:description="@string/permdesc_vibrate"
         android:protectionLevel="normal" />
 
-    <!-- Allows access to the flashlight -->
+    <!-- Allows access to the flashlight.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.FLASHLIGHT"
         android:label="@string/permlab_flashlight"
         android:description="@string/permdesc_flashlight"
         android:protectionLevel="normal" />
 
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
-         from dimming -->
+         from dimming.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.WAKE_LOCK"
         android:label="@string/permlab_wakeLock"
         android:description="@string/permdesc_wakeLock"
         android:protectionLevel="normal" />
 
-    <!-- Allows using the device's IR transmitter, if available -->
+    <!-- Allows using the device's IR transmitter, if available.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.TRANSMIT_IR"
         android:label="@string/permlab_transmitIr"
         android:description="@string/permdesc_transmitIr"
@@ -1014,7 +1099,9 @@
     <!-- ==================================================== -->
     <eat-comment />
 
-    <!-- Allows an application to modify global audio settings -->
+    <!-- Allows an application to modify global audio settings.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"
         android:label="@string/permlab_modifyAudioSettings"
         android:description="@string/permdesc_modifyAudioSettings"
@@ -1036,8 +1123,10 @@
     <permission android:name="android.permission.ACCESS_MTP"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows access to hardware peripherals.  Intended only for hardware testing.
-    <p>Not for use by third-party applications. -->
+    <!-- @SystemApi Allows access to hardware peripherals.  Intended only for hardware testing.
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.HARDWARE_TEST"
         android:protectionLevel="signature" />
 
@@ -1146,7 +1235,9 @@
         android:protectionLevel="system|signature" />
 
     <!-- Must be required by a {@link android.telecom.InCallService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: system|signature
+    -->
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
         android:protectionLevel="system|signature" />
 
@@ -1160,7 +1251,9 @@
         android:protectionLevel="system|signature" />
 
     <!-- Must be required by a {@link android.telecom.ConnectionService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: system|signature
+    -->
     <permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
         android:protectionLevel="system|signature" />
 
@@ -1185,7 +1278,9 @@
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to manage access to documents, usually as part
-         of a document picker. -->
+         of a document picker.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
         android:protectionLevel="signature" />
 
@@ -1194,7 +1289,9 @@
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Allows applications to disable the keyguard if it is not secure. -->
+    <!-- Allows applications to disable the keyguard if it is not secure.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.DISABLE_KEYGUARD"
         android:description="@string/permdesc_disableKeyguard"
         android:label="@string/permlab_disableKeyguard"
@@ -1261,7 +1358,9 @@
     <permission android:name="android.permission.GET_DETAILED_TASKS"
         android:protectionLevel="signature" />
 
-    <!-- Allows an application to change the Z-order of tasks -->
+    <!-- Allows an application to change the Z-order of tasks.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.REORDER_TASKS"
         android:label="@string/permlab_reorderTasks"
         android:description="@string/permdesc_reorderTasks"
@@ -1289,7 +1388,9 @@
         android:protectionLevel="normal" />
 
     <!-- Allows an application to call
-        {@link android.app.ActivityManager#killBackgroundProcesses}. -->
+        {@link android.app.ActivityManager#killBackgroundProcesses}.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
         android:label="@string/permlab_killBackgroundProcesses"
         android:description="@string/permdesc_killBackgroundProcesses"
@@ -1320,13 +1421,17 @@
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Allows applications to set the wallpaper -->
+    <!-- Allows applications to set the wallpaper.
+         <p>Protection level: normal
+     -->
     <permission android:name="android.permission.SET_WALLPAPER"
         android:label="@string/permlab_setWallpaper"
         android:description="@string/permdesc_setWallpaper"
         android:protectionLevel="normal" />
 
-    <!-- Allows applications to set the wallpaper hints -->
+    <!-- Allows applications to set the wallpaper hints.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.SET_WALLPAPER_HINTS"
         android:label="@string/permlab_setWallpaperHints"
         android:description="@string/permdesc_setWallpaperHints"
@@ -1342,7 +1447,9 @@
     <permission android:name="android.permission.SET_TIME"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows applications to set the system time zone -->
+    <!-- Allows applications to set the system time zone.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.SET_TIME_ZONE"
         android:label="@string/permlab_setTimeZone"
         android:description="@string/permdesc_setTimeZone"
@@ -1353,7 +1460,9 @@
     <!-- ==================================================== -->
     <eat-comment />
 
-    <!-- Allows an application to expand or collapse the status bar. -->
+    <!-- Allows an application to expand or collapse the status bar.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.EXPAND_STATUS_BAR"
         android:label="@string/permlab_expandStatusBar"
         android:description="@string/permdesc_expandStatusBar"
@@ -1364,13 +1473,17 @@
     <!-- ============================================================== -->
     <eat-comment />
 
-    <!-- Allows an application to install a shortcut in Launcher -->
+    <!-- Allows an application to install a shortcut in Launcher.
+         <p>Protection level: normal
+    -->
     <permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
         android:label="@string/permlab_install_shortcut"
         android:description="@string/permdesc_install_shortcut"
         android:protectionLevel="normal"/>
 
-    <!-- Allows an application to uninstall a shortcut in Launcher -->
+    <!-- Allows an application to uninstall a shortcut in Launcher.
+         <p>Protection level: normal
+    -->
     <permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
         android:label="@string/permlab_uninstall_shortcut"
         android:description="@string/permdesc_uninstall_shortcut"
@@ -1381,19 +1494,25 @@
     <!-- ==================================================== -->
     <eat-comment />
 
-    <!-- Allows applications to read the sync settings -->
+    <!-- Allows applications to read the sync settings.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.READ_SYNC_SETTINGS"
         android:description="@string/permdesc_readSyncSettings"
         android:label="@string/permlab_readSyncSettings"
         android:protectionLevel="normal" />
 
-    <!-- Allows applications to write the sync settings -->
+    <!-- Allows applications to write the sync settings.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.WRITE_SYNC_SETTINGS"
         android:description="@string/permdesc_writeSyncSettings"
         android:label="@string/permlab_writeSyncSettings"
         android:protectionLevel="normal" />
 
-    <!-- Allows applications to read the sync stats -->
+    <!-- Allows applications to read the sync stats.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.READ_SYNC_STATS"
         android:description="@string/permdesc_readSyncStats"
         android:label="@string/permlab_readSyncStats"
@@ -1451,7 +1570,9 @@
         android:description="@string/permdesc_persistentActivity"
         android:protectionLevel="normal" />
 
-    <!-- Allows an application to find out the space used by any package. -->
+    <!-- Allows an application to find out the space used by any package.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.GET_PACKAGE_SIZE"
         android:label="@string/permlab_getPackageSize"
         android:description="@string/permdesc_getPackageSize"
@@ -1473,7 +1594,9 @@
          system to start and allowing applications to have themselves
          running without the user being aware of them.  As such, you must
          explicitly declare your use of this facility to make that visible
-         to the user. -->
+         to the user.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
         android:label="@string/permlab_receiveBootCompleted"
         android:description="@string/permdesc_receiveBootCompleted"
@@ -1482,7 +1605,9 @@
     <!-- Allows an application to broadcast sticky intents.  These are
          broadcasts whose data is held by the system after being finished,
          so that clients can quickly retrieve that data without having
-         to wait for the next broadcast. -->
+         to wait for the next broadcast.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.BROADCAST_STICKY"
         android:label="@string/permlab_broadcastSticky"
         android:description="@string/permdesc_broadcastSticky"
@@ -1528,14 +1653,18 @@
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows applications to change network connectivity state -->
+    <!-- Allows applications to change network connectivity state.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.CHANGE_NETWORK_STATE"
         android:description="@string/permdesc_changeNetworkState"
         android:label="@string/permlab_changeNetworkState"
         android:protectionLevel="normal" />
 
     <!-- Allows an application to clear the caches of all installed
-         applications on the device.  -->
+         applications on the device.
+         <p>Protection level: system|signature
+    -->
     <permission android:name="android.permission.CLEAR_APP_CACHE"
         android:protectionLevel="signatureOrSystem" />
 
@@ -1634,9 +1763,11 @@
     <permission android:name="android.permission.STATUS_BAR_SERVICE"
         android:protectionLevel="signature" />
 
-    <!-- Allows an application to force a BACK operation on whatever is the
+    <!-- @SystemApi Allows an application to force a BACK operation on whatever is the
          top activity.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.FORCE_BACK"
         android:protectionLevel="signature" />
 
@@ -1654,15 +1785,19 @@
     <permission android:name="android.permission.UPDATE_APP_OPS_STATS"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows an application to open windows that are for use by parts
+    <!-- @SystemApi Allows an application to open windows that are for use by parts
          of the system user interface.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
         android:protectionLevel="signature" />
 
-    <!-- Allows an application to manage (create, destroy,
+    <!-- @SystemApi Allows an application to manage (create, destroy,
          Z-order) application tokens in the window manager.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.MANAGE_APP_TOKENS"
         android:protectionLevel="signature" />
 
@@ -1671,10 +1806,12 @@
     <permission android:name="android.permission.FREEZE_SCREEN"
         android:protectionLevel="signature" />
 
-    <!-- Allows an application to inject user events (keys, touch, trackball)
+    <!-- @SystemApi Allows an application to inject user events (keys, touch, trackball)
          into the event stream and deliver them to ANY window.  Without this
          permission, you can only deliver events to windows in your own process.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.INJECT_EVENTS"
         android:protectionLevel="signature" />
 
@@ -1695,10 +1832,12 @@
     <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
         android:protectionLevel="signature" />
 
-    <!-- Allows an application to watch and control how activities are
+    <!-- @SystemApi Allows an application to watch and control how activities are
          started globally in the system.  Only for is in debugging
          (usually the monkey command).
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.SET_ACTIVITY_WATCHER"
         android:protectionLevel="signature" />
 
@@ -1716,9 +1855,11 @@
     <permission android:name="android.permission.STOP_APP_SWITCHES"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows an application to retrieve private information about
+    <!-- @SystemApi Allows an application to retrieve private information about
          the current top activity, such as any assist context it can provide.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
         android:protectionLevel="signature" />
 
@@ -1730,28 +1871,38 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_INPUT_METHOD"
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.media.midi.MidiDeviceService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_MIDI_DEVICE_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.printservice.PrintService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_PRINT_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
          or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
-         the system can bind to it. -->
+         the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_NFC_SERVICE"
         android:protectionLevel="signature" />
 
@@ -1761,22 +1912,30 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by a TextService (e.g. SpellCheckerService)
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_TEXT_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.net.VpnService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_VPN_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: system|signature
+    -->
     <permission android:name="android.permission.BIND_WALLPAPER"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_VOICE_INTERACTION"
         android:protectionLevel="signature" />
 
@@ -1793,7 +1952,9 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.media.tv.TvInputService}
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_TV_INPUT"
         android:protectionLevel="signature|system" />
 
@@ -1810,7 +1971,9 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by device administration receiver, to ensure that only the
-         system can interact with it. -->
+         system can interact with it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_DEVICE_ADMIN"
         android:protectionLevel="signature" />
 
@@ -1820,14 +1983,18 @@
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows low-level access to setting the orientation (actually
+    <!-- @SystemApi Allows low-level access to setting the orientation (actually
          rotation) of the screen.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.SET_ORIENTATION"
         android:protectionLevel="signature" />
 
-    <!-- Allows low-level access to setting the pointer speed.
-         <p>Not for use by third-party applications. -->
+    <!-- @SystemApi Allows low-level access to setting the pointer speed.
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.SET_POINTER_SPEED"
         android:protectionLevel="signature" />
 
@@ -1845,7 +2012,9 @@
 
     <!-- Allows an application to request installing packages. Apps
          targeting APIs greater than 22 must hold this permission in
-         order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.-->
+         order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
         android:label="@string/permlab_requestInstallPackages"
         android:description="@string/permdesc_requestInstallPackages"
@@ -1856,8 +2025,10 @@
     <permission android:name="android.permission.INSTALL_PACKAGES"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows an application to clear user data.
-    <p>Not for use by third-party applications. -->
+    <!-- @SystemApi Allows an application to clear user data.
+         <p>Not for use by third-party applications
+         @hide
+    -->
     <permission android:name="android.permission.CLEAR_APP_USER_DATA"
         android:protectionLevel="signature" />
 
@@ -1890,8 +2061,10 @@
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
         android:protectionLevel="signatureOrSystem" />
 
-    <!-- Allows an application to use SurfaceFlinger's low level features.
-    <p>Not for use by third-party applications. -->
+    <!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
         android:protectionLevel="signature" />
 
@@ -1957,8 +2130,10 @@
     <permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
         android:protectionLevel="signature|system" />
 
-    <!-- Required to be able to disable the device (very dangerous!).
-    <p>Not for use by third-party applications.. -->
+    <!-- @SystemApi Required to be able to disable the device (very dangerous!).
+         <p>Not for use by third-party applications.
+         @hide
+    -->
     <permission android:name="android.permission.BRICK"
         android:protectionLevel="signature" />
 
@@ -1967,9 +2142,11 @@
     <permission android:name="android.permission.REBOOT"
         android:protectionLevel="signature|system" />
 
-   <!-- Allows low-level access to power management.
-   <p>Not for use by third-party applications. -->
-    <permission android:name="android.permission.DEVICE_POWER"
+   <!-- @SystemApi Allows low-level access to power management.
+        <p>Not for use by third-party applications.
+        @hide
+    -->
+   <permission android:name="android.permission.DEVICE_POWER"
         android:protectionLevel="signature" />
 
    <!-- Allows access to the PowerManager.userActivity function.
@@ -1983,23 +2160,27 @@
 
     <!-- Run as a manufacturer test application, running as the root user.
          Only available when the device is running in manufacturer test mode.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+    -->
     <permission android:name="android.permission.FACTORY_TEST"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast a notification that an application
          package has been removed.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+    -->
     <permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast an SMS receipt notification.
-    <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+    -->
     <permission android:name="android.permission.BROADCAST_SMS"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast a WAP PUSH receipt notification.
-    <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+    -->
     <permission android:name="android.permission.BROADCAST_WAP_PUSH"
         android:protectionLevel="signature" />
 
@@ -2242,7 +2423,9 @@
     <permission android:name="android.permission.ACCESS_NOTIFICATIONS"
         android:protectionLevel="signature|system" />
 
-    <!-- Marker permission for applications that wish to access notification policy. -->
+    <!-- Marker permission for applications that wish to access notification policy.
+         <p>Protection level: normal
+    -->
     <permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
         android:description="@string/permdesc_access_notification_policy"
         android:label="@string/permlab_access_notification_policy"
@@ -2286,13 +2469,17 @@
 
     <!-- Must be required by an {@link
          android.service.notification.NotificationListenerService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link
          android.service.chooser.ChooserTargetService}, to ensure that
-         only the system can bind to it. -->
+         only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
         android:protectionLevel="signature" />
 
@@ -2304,7 +2491,9 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.service.dreams.DreamService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
     <permission android:name="android.permission.BIND_DREAM_SERVICE"
         android:protectionLevel="signature" />
 
@@ -2359,7 +2548,9 @@
 
     <!-- The system process that is allowed to bind to services in carrier apps will
          have this permission. Carrier apps should use this permission to protect
-         their services that only the system is allowed to bind to. -->
+         their services that only the system is allowed to bind to.
+         <p>Protection level: system|signature
+    -->
     <permission android:name="android.permission.BIND_CARRIER_SERVICES"
         android:label="@string/permlab_bindCarrierServices"
         android:description="@string/permdesc_bindCarrierServices"
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
index 1b58ce5..482f91f 100644
--- a/core/res/res/layout/floating_popup_menu_button.xml
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -18,7 +18,8 @@
 <Button xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="match_parent"
-    android:minWidth="@dimen/floating_toolbar_menu_button_side_padding"
+    android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
+    android:minHeight="@dimen/floating_toolbar_height"
     android:paddingStart="@dimen/floating_toolbar_menu_button_side_padding"
     android:paddingEnd="@dimen/floating_toolbar_menu_button_side_padding"
     android:paddingTop="0dp"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 33c9c60b..fd47d49 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -27,6 +27,9 @@
         <!-- ============== -->
         <eat-comment />
 
+        <!-- Specifies that a theme has a light background with dark text on top.  -->
+        <attr name="isLightTheme" format="boolean" />
+
         <!-- Default color of foreground imagery. -->
         <attr name="colorForeground" format="color" />
         <!-- Default color of foreground imagery on an inverted background. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3a1a156..5c42d04 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -240,6 +240,7 @@
   <java-symbol type="attr" name="windowFixedHeightMajor" />
   <java-symbol type="attr" name="windowFixedHeightMinor" />
   <java-symbol type="attr" name="accessibilityFocusedDrawable"/>
+  <java-symbol type="attr" name="isLightTheme"/>
 
   <java-symbol type="bool" name="action_bar_embed_tabs" />
   <java-symbol type="bool" name="action_bar_embed_tabs_pre_jb" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b7acdd4..c230645 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -42,6 +42,7 @@
     -->
     <style name="Theme">
 
+        <item name="isLightTheme">false</item>
         <item name="colorForeground">@color/bright_foreground_dark</item>
         <item name="colorForegroundInverse">@color/bright_foreground_dark_inverse</item>
         <item name="colorBackground">@color/background_dark</item>
@@ -472,6 +473,7 @@
          background will be a light color.
          <p>This is designed for API level 10 and lower.</p>-->
     <style name="Theme.Light">
+        <item name="isLightTheme">true</item>
         <item name="windowBackground">@drawable/screen_background_selector_light</item>
         <item name="windowClipToOutline">false</item>
 
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 9548e51..5783a49 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -92,11 +92,13 @@
     <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}" />
 
     <!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
-         http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements -->
+         http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
+         visual voicemail code for Orange: 21101 -->
     <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101" />
 
     <!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
-         http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf -->
+         http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf,
+         visual voicemail code for EE: 887 -->
     <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|887" />
 
     <!-- Georgia: 4 digits, known premium codes listed -->
@@ -183,7 +185,8 @@
     <!-- Ukraine: 4 digits, known premium codes listed -->
     <shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
 
-    <!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm) -->
+    <!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
+         visual voicemail code for T-Mobile: 122 -->
     <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" free="122|87902" />
 
 </shortcodes>
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
new file mode 100644
index 0000000..d2e2131
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.format;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.format.Formatter.BytesResult;
+
+import java.util.Locale;
+
+public class FormatterTest extends AndroidTestCase {
+
+    private Locale mOriginalLocale;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mOriginalLocale = mContext.getResources().getConfiguration().locale;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mOriginalLocale != null) {
+            setLocale(mOriginalLocale);
+        }
+        super.tearDown();
+    }
+
+    private void setLocale(Locale locale) {
+        Resources res = getContext().getResources();
+        Configuration config = res.getConfiguration();
+        config.locale = locale;
+        res.updateConfiguration(config, res.getDisplayMetrics());
+
+        Locale.setDefault(locale);
+    }
+
+    @SmallTest
+    public void testFormatBytes() {
+        setLocale(Locale.ENGLISH);
+
+        checkFormatBytes(0, true, "0.00", 0);
+        checkFormatBytes(0, false, "0.00", 0);
+
+        checkFormatBytes(1, true, "1.0", 1);
+        checkFormatBytes(1, false, "1.00", 1);
+
+        checkFormatBytes(12, true, "12", 12);
+        checkFormatBytes(12, false, "12.00", 12);
+
+        checkFormatBytes(123, true, "123", 123);
+        checkFormatBytes(123, false, "123", 123);
+
+        checkFormatBytes(812, true, "812", 812);
+        checkFormatBytes(812, false, "812", 812);
+
+        checkFormatBytes(912, true, "0.89", 911);
+        checkFormatBytes(912, false, "0.89", 911);
+
+        checkFormatBytes(9123, true, "8.9", 9113);
+        checkFormatBytes(9123, false, "8.91", 9123);
+
+        checkFormatBytes(9123000, true, "8.7", 9122611);
+        checkFormatBytes(9123000, false, "8.70", 9122611);
+
+        // The method doesn't really support negative values, but apparently people pass -1...
+        checkFormatBytes(-1, true, "-1.00", -1);
+        checkFormatBytes(-1, false, "-1.00", -1);
+
+        // Missing FLAG_CALCULATE_ROUNDED case.
+        BytesResult r = Formatter.formatBytes(getContext().getResources(), 1, 0);
+        assertEquals("1.00", r.value);
+        assertEquals(0, r.roundedBytes); // Didn't pass FLAG_CALCULATE_ROUNDED
+
+        // Make sure it works on different locales.
+        setLocale(new Locale("es", "ES"));
+        checkFormatBytes(9123000, false, "8,70", 9122611);
+    }
+
+    private void checkFormatBytes(long bytes, boolean useShort,
+            String expectedString, long expectedRounded) {
+        BytesResult r = Formatter.formatBytes(getContext().getResources(), bytes,
+                Formatter.FLAG_CALCULATE_ROUNDED | (useShort ? Formatter.FLAG_SHORTER : 0));
+        assertEquals(expectedString, r.value);
+        assertEquals(expectedRounded, r.roundedBytes);
+    }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index c517201..377e6a16 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -58,21 +58,6 @@
         <group gid="log" />
     </permission>
 
-    <permission name="android.permission.READ_EXTERNAL_STORAGE" perUser="true" >
-        <group gid="sdcard_r" />
-    </permission>
-
-    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" perUser="true" >
-        <group gid="sdcard_r" />
-        <group gid="sdcard_rw" />
-    </permission>
-
-    <permission name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" >
-        <group gid="sdcard_r" />
-        <group gid="sdcard_rw" />
-        <group gid="sdcard_all" />
-    </permission>
-
     <permission name="android.permission.WRITE_MEDIA_STORAGE" >
         <group gid="media_rw" />
     </permission>
diff --git a/docs/html/guide/topics/security/permissions.jd b/docs/html/guide/topics/security/permissions.jd
index 6f919da..cfab3c9 100644
--- a/docs/html/guide/topics/security/permissions.jd
+++ b/docs/html/guide/topics/security/permissions.jd
@@ -52,9 +52,7 @@
 <em>permissions</em> they need for additional capabilities not provided by
 the basic sandbox. Applications statically declare the permissions they
 require, and the Android system prompts the user for consent at the time the
-application is installed. Android has no mechanism for granting permissions
-dynamically (at run-time) because it complicates the user experience to the
-detriment of security.</p>
+application is installed.</p>
 
 <p>The application sandbox does not depend on the technology used to build
 an application. In particular the Dalvik VM is not a security boundary, and
diff --git a/include/androidfw/ZipFileRO.h b/include/androidfw/ZipFileRO.h
index 1410d87..7680342 100644
--- a/include/androidfw/ZipFileRO.h
+++ b/include/androidfw/ZipFileRO.h
@@ -91,6 +91,7 @@
      * a matching call to endIteration with the same cookie.
      */
     bool startIteration(void** cookie);
+    bool startIteration(void** cookie, const char* prefix, const char* suffix);
 
     /**
      * Return the next entry in iteration order, or NULL if there are no more
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index 50f3ed4..38cacd0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -731,6 +731,21 @@
         return mMainDataStreamer.getProducedOutputSizeBytes();
     }
 
+    static String opmodeToString(int opmode) {
+        switch (opmode) {
+            case Cipher.ENCRYPT_MODE:
+                return "ENCRYPT_MODE";
+            case Cipher.DECRYPT_MODE:
+                return "DECRYPT_MODE";
+            case Cipher.WRAP_MODE:
+                return "WRAP_MODE";
+            case Cipher.UNWRAP_MODE:
+                return "UNWRAP_MODE";
+            default:
+                return String.valueOf(opmode);
+        }
+    }
+
     // The methods below need to be implemented by subclasses.
 
     /**
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index 8e58195..94ed8b4 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -60,9 +60,10 @@
         }
 
         @Override
-        protected boolean isEncryptingUsingPrivateKeyPermitted() {
-            // RSA encryption with no padding using private key is is a way to implement raw RSA
-            // signatures. We have to support this.
+        protected boolean adjustConfigForEncryptingWithPrivateKey() {
+            // RSA encryption with no padding using private key is a way to implement raw RSA
+            // signatures which JCA does not expose via Signature. We thus have to support this.
+            setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
             return true;
         }
 
@@ -198,6 +199,15 @@
         }
 
         @Override
+        protected boolean adjustConfigForEncryptingWithPrivateKey() {
+            // RSA encryption with PCKS#1 padding using private key is a way to implement RSA
+            // signatures with PKCS#1 padding. We have to support this for legacy reasons.
+            setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
+            setKeymasterPaddingOverride(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
+            return true;
+        }
+
+        @Override
         protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
 
         @Override
@@ -425,6 +435,7 @@
     }
 
     private final int mKeymasterPadding;
+    private int mKeymasterPaddingOverride;
 
     private int mModulusSizeBytes = -1;
 
@@ -458,20 +469,15 @@
                     // Permitted
                     break;
                 case Cipher.ENCRYPT_MODE:
-                    if (!isEncryptingUsingPrivateKeyPermitted()) {
+                case Cipher.WRAP_MODE:
+                    if (!adjustConfigForEncryptingWithPrivateKey()) {
                         throw new InvalidKeyException(
-                                "RSA private keys cannot be used with Cipher.ENCRYPT_MODE"
+                                "RSA private keys cannot be used with " + opmodeToString(opmode)
+                                + " and padding "
+                                + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
                                 + ". Only RSA public keys supported for this mode");
                     }
-                    // JCA doesn't provide a way to generate raw RSA signatures (with arbitrary
-                    // padding). Thus, encrypting with private key is used instead.
-                    setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
                     break;
-                case Cipher.WRAP_MODE:
-                    throw new InvalidKeyException(
-                            "RSA private keys cannot be used with Cipher.WRAP_MODE"
-                            + ". Only RSA public keys supported for this mode");
-                    // break;
                 default:
                     throw new InvalidKeyException(
                             "RSA private keys cannot be used with opmode: " + opmode);
@@ -485,12 +491,15 @@
                     break;
                 case Cipher.DECRYPT_MODE:
                 case Cipher.UNWRAP_MODE:
-                    throw new InvalidKeyException("RSA public keys cannot be used with opmode: "
-                            + opmode + ". Only RSA private keys supported for this opmode.");
+                    throw new InvalidKeyException(
+                            "RSA public keys cannot be used with " + opmodeToString(opmode)
+                            + " and padding "
+                            + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
+                            + ". Only RSA private keys supported for this opmode.");
                     // break;
                 default:
                     throw new InvalidKeyException(
-                            "RSA public keys cannot be used with opmode: " + opmode);
+                            "RSA public keys cannot be used with " + opmodeToString(opmode));
             }
         }
 
@@ -511,13 +520,22 @@
         setKey(keystoreKey);
     }
 
-    protected boolean isEncryptingUsingPrivateKeyPermitted() {
+    /**
+     * Adjusts the configuration of this cipher for encrypting using the private key.
+     *
+     * <p>The default implementation does nothing and refuses to adjust the configuration.
+     *
+     * @return {@code true} if the configuration has been adjusted, {@code false} if encrypting
+     *         using private key is not permitted for this cipher.
+     */
+    protected boolean adjustConfigForEncryptingWithPrivateKey() {
         return false;
     }
 
     @Override
     protected final void resetAll() {
         mModulusSizeBytes = -1;
+        mKeymasterPaddingOverride = -1;
         super.resetAll();
     }
 
@@ -530,7 +548,11 @@
     protected void addAlgorithmSpecificParametersToBegin(
             @NonNull KeymasterArguments keymasterArgs) {
         keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
+        int keymasterPadding = getKeymasterPaddingOverride();
+        if (keymasterPadding == -1) {
+            keymasterPadding = mKeymasterPadding;
+        }
+        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
         int purposeOverride = getKeymasterPurposeOverride();
         if ((purposeOverride != -1)
                 && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
@@ -568,4 +590,15 @@
         }
         return mModulusSizeBytes;
     }
+
+    /**
+     * Overrides the default padding of the crypto operation.
+     */
+    protected final void setKeymasterPaddingOverride(int keymasterPadding) {
+        mKeymasterPaddingOverride = keymasterPadding;
+    }
+
+    protected final int getKeymasterPaddingOverride() {
+        return mKeymasterPaddingOverride;
+    }
 }
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 6f927b4..a6f6d8c 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -126,10 +126,18 @@
     return true;
 }
 
-bool ZipFileRO::startIteration(void** cookie)
+bool ZipFileRO::startIteration(void** cookie) {
+  return startIteration(cookie, NULL, NULL);
+}
+
+bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix)
 {
     _ZipEntryRO* ze = new _ZipEntryRO;
-    int32_t error = StartIteration(mHandle, &(ze->cookie), NULL /* prefix */);
+    ZipEntryName pe(prefix ? prefix : "");
+    ZipEntryName se(suffix ? suffix : "");
+    int32_t error = StartIteration(mHandle, &(ze->cookie),
+                                   prefix ? &pe : NULL,
+                                   suffix ? &se : NULL);
     if (error) {
         ALOGW("Could not start iteration over %s: %s", mFileName, ErrorCodeString(error));
         delete ze;
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 024ff10..09d1258 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -21,6 +21,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <utils/Vector.h>
+#include <utils/MathUtils.h>
 
 #include "AmbientShadow.h"
 #include "Properties.h"
@@ -172,6 +173,8 @@
     // acos( )     --- [0, M_PI]
     // floor(...)  --- [0, EXTRA_VERTEX_PER_PI]
     float dotProduct = vector1.dot(vector2);
+    // make sure that dotProduct value is in acsof input range [-1, 1]
+    dotProduct = MathUtils::clamp(dotProduct, -1.0f, 1.0f);
     // TODO: Use look up table for the dotProduct to extraVerticesNumber
     // computation, if needed.
     float angle = acosf(dotProduct);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 6c26220..28d0713 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -705,6 +705,9 @@
 
             int maxInstances = Utils.parseIntSafely(
                     map.get("max-supported-instances"), mMaxSupportedInstances);
+            // TODO: replace all max-supported-instances with max-concurrent-instances.
+            maxInstances = Utils.parseIntSafely(
+                    map.get("max-concurrent-instances"), maxInstances);
             mMaxSupportedInstances =
                     Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index ac9dc85..d265e0d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -50,7 +50,7 @@
         mAppearAnimationUtils = new AppearAnimationUtils(context);
         mDisappearAnimationUtils = new DisappearAnimationUtils(context,
                 125, 0.6f /* translationScale */,
-                0.6f /* delayScale */, AnimationUtils.loadInterpolator(
+                0.45f /* delayScale */, AnimationUtils.loadInterpolator(
                         mContext, android.R.interpolator.fast_out_linear_in));
         mDisappearYTranslation = getResources().getDimensionPixelSize(
                 R.dimen.disappear_y_translation);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 59a8ad5..3568429 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -109,7 +109,7 @@
                         mContext, android.R.interpolator.linear_out_slow_in));
         mDisappearAnimationUtils = new DisappearAnimationUtils(context,
                 125, 1.2f /* translationScale */,
-                0.8f /* delayScale */, AnimationUtils.loadInterpolator(
+                0.6f /* delayScale */, AnimationUtils.loadInterpolator(
                         mContext, android.R.interpolator.fast_out_linear_in));
         mDisappearYTranslation = getResources().getDimensionPixelSize(
                 R.dimen.disappear_y_translation);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 44b9d8b..41043eb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -905,7 +905,9 @@
     private boolean mutateSystemSetting(String name, String value, int runAsUserId,
             int operation) {
         // Check for permissions first.
-        hasPermissionsToMutateSystemSettings();
+        if (!hasPermissionsToMutateSystemSettings()) {
+            return false;
+        }
 
         // Verify whether this operation is allowed for the calling package.
         if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 005077f..155f5ea 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -583,7 +583,7 @@
     <dimen name="managed_profile_toast_padding">4dp</dimen>
 
     <!-- Thickness of the assist disclosure beams -->
-    <dimen name="assist_disclosure_thickness">4dp</dimen>
+    <dimen name="assist_disclosure_thickness">3dp</dimen>
 
     <!-- Thickness of the shadows of the assist disclosure beams -->
     <dimen name="assist_disclosure_shadow_thickness">1.5dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 29d2a01..3657cf2 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -44,6 +44,7 @@
     })
     public @interface Key {
         String SEARCH_APP_WIDGET_ID = "searchAppWidgetId";
+        String SEARCH_APP_WIDGET_PACKAGE = "searchAppWidgetPackage";
         String DEBUG_MODE_ENABLED = "debugModeEnabled";
         String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed";
         String COLOR_INVERSION_TILE_LAST_USED = "ColorInversionTileLastUsed";
@@ -80,6 +81,14 @@
         get(context).edit().putLong(key, value).apply();
     }
 
+    public static String getString(Context context, @Key String key, String defaultValue) {
+        return get(context).getString(key, defaultValue);
+    }
+
+    public static void putString(Context context, @Key String key, String value) {
+        get(context).edit().putString(key, value).apply();
+    }
+
     public static Map<String, ?> getAll(Context context) {
         return get(context).getAll();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 7838119..6ba5626 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -125,14 +125,11 @@
         }
     }
 
-    public void onGestureInvoked(boolean vibrate) {
+    public void onGestureInvoked() {
         if (mAssistComponent == null) {
             return;
         }
 
-        if (vibrate) {
-            vibrate();
-        }
         final boolean isService = isAssistantService();
         if (isService || !isVoiceSessionRunning()) {
             showOrb();
@@ -290,10 +287,6 @@
         v.setImageDrawable(null);
     }
 
-    private void vibrate() {
-        mView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-    }
-
     private boolean isAssistantService() {
         return mAssistComponent == null ?
                 false : mAssistComponent.equals(getVoiceInteractorComponentName());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 89c456c..6a45369 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -20,7 +20,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ITaskStackListener;
-import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -37,11 +36,10 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.MutableBoolean;
-import android.util.Pair;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
-
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
@@ -170,6 +168,7 @@
     Handler mHandler;
     TaskStackListenerImpl mTaskStackListener;
     RecentsOwnerEventProxyReceiver mProxyBroadcastReceiver;
+    RecentsAppWidgetHost mAppWidgetHost;
     boolean mBootCompleted;
     boolean mStartAnimationTriggered;
     boolean mCanReuseTaskStackViews = true;
@@ -235,6 +234,7 @@
         mSystemServicesProxy = new SystemServicesProxy(mContext);
         mHandler = new Handler();
         mTaskStackBounds = new Rect();
+        mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
 
         // Register the task stack listener
         mTaskStackListener = new TaskStackListenerImpl(mHandler);
@@ -255,7 +255,7 @@
         // Initialize some static datastructures
         TaskStackViewLayoutAlgorithm.initializeCurve();
         // Load the header bar layout
-        reloadHeaderBarLayout(true);
+        reloadHeaderBarLayout();
 
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
@@ -488,11 +488,11 @@
         // Don't reuse task stack views if the configuration changes
         mCanReuseTaskStackViews = false;
         // Reload the header bar layout
-        reloadHeaderBarLayout(false);
+        reloadHeaderBarLayout();
     }
 
     /** Prepares the header bar layout. */
-    void reloadHeaderBarLayout(boolean reloadWidget) {
+    void reloadHeaderBarLayout() {
         Resources res = mContext.getResources();
         mWindowRect = mSystemServicesProxy.getWindowRect();
         mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
@@ -500,12 +500,16 @@
         mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
         mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
         mConfig.updateOnConfigurationChange();
-        if (reloadWidget) {
-            // Reload the widget id before we get the task stack bounds
-            reloadSearchBarAppWidget(mContext, mSystemServicesProxy);
+        Rect searchBarBounds = new Rect();
+        // Try and pre-emptively bind the search widget on startup to ensure that we
+        // have the right thumbnail bounds to animate to.
+        // Note: We have to reload the widget id before we get the task stack bounds below
+        if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
+            mConfig.getSearchBarBounds(mWindowRect.width(), mWindowRect.height(),
+                    mStatusBarHeight, searchBarBounds);
         }
         mConfig.getAvailableTaskStackBounds(mWindowRect.width(), mWindowRect.height(),
-                mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
+                mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), searchBarBounds,
                 mTaskStackBounds);
         if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
             mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
@@ -532,24 +536,6 @@
         }
     }
 
-    /** Prepares the search bar app widget */
-    void reloadSearchBarAppWidget(Context context, SystemServicesProxy ssp) {
-        // Try and pre-emptively bind the search widget on startup to ensure that we
-        // have the right thumbnail bounds to animate to.
-        if (Constants.DebugFlags.App.EnableSearchLayout) {
-            // If there is no id, then bind a new search app widget
-            if (mConfig.searchBarAppWidgetId < 0) {
-                AppWidgetHost host = new RecentsAppWidgetHost(context,
-                        Constants.Values.App.AppWidgetHostId);
-                Pair<Integer, AppWidgetProviderInfo> widgetInfo = ssp.bindSearchAppWidget(host);
-                if (widgetInfo != null) {
-                    // Save the app widget id into the settings
-                    mConfig.updateSearchBarAppWidgetId(context, widgetInfo.first);
-                }
-            }
-        }
-    }
-
     /** Toggles the recents activity */
     void toggleRecentsActivity() {
         // If the user has toggled it too quickly, then just eat up the event here (it's better than
@@ -799,27 +785,13 @@
             // If there is no thumbnail transition, but is launching from home into recents, then
             // use a quick home transition and do the animation from home
             if (hasRecentTasks) {
-                // Get the home activity info
                 String homeActivityPackage = mSystemServicesProxy.getHomeActivityPackageName();
-                // Get the search widget info
-                AppWidgetProviderInfo searchWidget = null;
-                String searchWidgetPackage = null;
-                if (mConfig.hasSearchBarAppWidget()) {
-                    searchWidget = mSystemServicesProxy.getAppWidgetInfo(
-                            mConfig.searchBarAppWidgetId);
-                } else {
-                    searchWidget = mSystemServicesProxy.resolveSearchAppWidget();
-                }
-                if (searchWidget != null && searchWidget.provider != null) {
-                    searchWidgetPackage = searchWidget.provider.getPackageName();
-                }
-                // Determine whether we are coming from a search owned home activity
-                boolean fromSearchHome = false;
-                if (homeActivityPackage != null && searchWidgetPackage != null &&
-                        homeActivityPackage.equals(searchWidgetPackage)) {
-                    fromSearchHome = true;
-                }
+                String searchWidgetPackage =
+                        Prefs.getString(mContext, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null);
 
+                // Determine whether we are coming from a search owned home activity
+                boolean fromSearchHome = (homeActivityPackage != null) &&
+                        homeActivityPackage.equals(searchWidgetPackage);
                 ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
                 startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
                         false /* fromThumbnail */, stackVr);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index da7247c..bf15c68 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -28,7 +28,6 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.util.Pair;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewStub;
@@ -50,7 +49,6 @@
 import com.android.systemui.recents.views.ViewAnimation;
 
 import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 
 /**
@@ -75,9 +73,9 @@
     RecentsResizeTaskDialog mResizeTaskDebugDialog;
 
     // Search AppWidget
-    AppWidgetProviderInfo mSearchAppWidgetInfo;
+    AppWidgetProviderInfo mSearchWidgetInfo;
     RecentsAppWidgetHost mAppWidgetHost;
-    RecentsAppWidgetHostView mSearchAppWidgetHostView;
+    RecentsAppWidgetHostView mSearchWidgetHostView;
 
     // Runnables to finish the Recents activity
     FinishRecentsRunnable mFinishLaunchHomeRunnable;
@@ -168,8 +166,10 @@
                 // When the screen turns off, dismiss Recents to Home
                 dismissRecentsToHome(false);
             } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
-                // When the search activity changes, update the Search widget
-                refreshSearchWidget();
+                // When the search activity changes, update the search widget view
+                SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+                mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(context, mAppWidgetHost);
+                refreshSearchWidgetView();
             }
         }
     };
@@ -253,7 +253,7 @@
             if (mRecentsView.hasValidSearchBar()) {
                 mRecentsView.setSearchBarVisibility(View.VISIBLE);
             } else {
-                addSearchBarAppWidgetView();
+                refreshSearchWidgetView();
             }
         }
 
@@ -261,60 +261,6 @@
         mScrimViews.prepareEnterRecentsAnimation();
     }
 
-    /** Attempts to allocate and bind the search bar app widget */
-    void bindSearchBarAppWidget() {
-        if (Constants.DebugFlags.App.EnableSearchLayout) {
-            SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-
-            // Reset the host view and widget info
-            mSearchAppWidgetHostView = null;
-            mSearchAppWidgetInfo = null;
-
-            // Try and load the app widget id from the settings
-            int appWidgetId = mConfig.searchBarAppWidgetId;
-            if (appWidgetId >= 0) {
-                mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId);
-                if (mSearchAppWidgetInfo == null) {
-                    // If there is no actual widget associated with that id, then delete it and
-                    // prepare to bind another app widget in its place
-                    ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
-                    appWidgetId = -1;
-                }
-            }
-
-            // If there is no id, then bind a new search app widget
-            if (appWidgetId < 0) {
-                Pair<Integer, AppWidgetProviderInfo> widgetInfo =
-                        ssp.bindSearchAppWidget(mAppWidgetHost);
-                if (widgetInfo != null) {
-                    // Save the app widget id into the settings
-                    mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first);
-                    mSearchAppWidgetInfo = widgetInfo.second;
-                }
-            }
-        }
-    }
-
-    /** Creates the search bar app widget view */
-    void addSearchBarAppWidgetView() {
-        if (Constants.DebugFlags.App.EnableSearchLayout) {
-            int appWidgetId = mConfig.searchBarAppWidgetId;
-            if (appWidgetId >= 0) {
-                mSearchAppWidgetHostView = (RecentsAppWidgetHostView) mAppWidgetHost.createView(
-                        this, appWidgetId, mSearchAppWidgetInfo);
-                Bundle opts = new Bundle();
-                opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                        AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
-                mSearchAppWidgetHostView.updateAppWidgetOptions(opts);
-                // Set the padding to 0 for this search widget
-                mSearchAppWidgetHostView.setPadding(0, 0, 0, 0);
-                mRecentsView.setSearchBar(mSearchAppWidgetHostView);
-            } else {
-                mRecentsView.setSearchBar(null);
-            }
-        }
-    }
-
     /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
     boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
@@ -393,7 +339,7 @@
         inflateDebugOverlay();
 
         // Bind the search app widget when we first start up
-        bindSearchBarAppWidget();
+        mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
 
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
@@ -498,7 +444,8 @@
         ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
         ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
         mRecentsView.startEnterRecentsAnimation(ctx);
-        if (mConfig.searchBarAppWidgetId >= 0) {
+
+        if (mSearchWidgetInfo != null) {
             final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> cbRef =
                     new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>(
                             RecentsActivity.this);
@@ -654,9 +601,22 @@
     /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/
 
     @Override
-    public void refreshSearchWidget() {
-        bindSearchBarAppWidget();
-        addSearchBarAppWidgetView();
+    public void refreshSearchWidgetView() {
+        if (mSearchWidgetInfo != null) {
+            SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+            int searchWidgetId = ssp.getSearchAppWidgetId(this);
+            mSearchWidgetHostView = (RecentsAppWidgetHostView) mAppWidgetHost.createView(
+                    this, searchWidgetId, mSearchWidgetInfo);
+            Bundle opts = new Bundle();
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                    AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
+            mSearchWidgetHostView.updateAppWidgetOptions(opts);
+            // Set the padding to 0 for this search widget
+            mSearchWidgetHostView.setPadding(0, 0, 0, 0);
+            mRecentsView.setSearchBar(mSearchWidgetHostView);
+        } else {
+            mRecentsView.setSearchBar(null);
+        }
     }
 
     /**** DebugOverlayView.DebugOverlayViewCallbacks ****/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index d4e50f8..0102332 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -20,26 +20,20 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoader;
 
 /** Our special app widget host for the Search widget */
 public class RecentsAppWidgetHost extends AppWidgetHost {
 
     /* Callbacks to notify when an app package changes */
     interface RecentsAppWidgetHostCallbacks {
-        public void refreshSearchWidget();
+        void refreshSearchWidgetView();
     }
 
-    Context mContext;
     RecentsAppWidgetHostCallbacks mCb;
-    RecentsConfiguration mConfig;
     boolean mIsListening;
 
     public RecentsAppWidgetHost(Context context, int hostId) {
         super(context, hostId);
-        mContext = context;
-        mConfig = RecentsConfiguration.getInstance();
     }
 
     public void startListening(RecentsAppWidgetHostCallbacks cb) {
@@ -57,7 +51,6 @@
         }
         // Ensure that we release any references to the callbacks
         mCb = null;
-        mContext = null;
         mIsListening = false;
     }
 
@@ -67,18 +60,14 @@
         return new RecentsAppWidgetHostView(context);
     }
 
+    /**
+     * Note: this is only called for packages that have updated, not removed.
+     */
     @Override
     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
-        if (mCb == null) return;
-        if (mContext == null) return;
-
-        SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-        if (appWidgetId > -1 && appWidgetId == mConfig.searchBarAppWidgetId) {
-            // The search provider may have changed, so just delete the old widget and bind it again
-            ssp.unbindSearchAppWidget(this, appWidgetId);
-            // Update the search widget
-            mConfig.updateSearchBarAppWidgetId(mContext, -1);
-            mCb.refreshSearchWidget();
+        super.onProviderChanged(appWidgetId, appWidgetInfo);
+        if (mIsListening && mCb != null) {
+            mCb.refreshSearchWidgetView();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
index 1ed755a..672d602 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
@@ -18,6 +18,7 @@
 
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
+import android.view.View;
 import android.widget.RemoteViews;
 
 public class RecentsAppWidgetHostView extends AppWidgetHostView {
@@ -37,6 +38,14 @@
         super.updateAppWidget(remoteViews);
     }
 
+    @Override
+    protected View getErrorView() {
+        // Just return an empty view as the error view when failing to inflate the Recents search
+        // bar widget (this is mainly to catch the case where we try and inflate the widget view
+        // while the search provider is updating)
+        return new View(mContext);
+    }
+
     /**
      * Updates the last orientation that this widget was inflated.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 244fada..dfe7e96 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -73,7 +73,6 @@
     public int maxNumTasksToLoad;
 
     /** Search bar */
-    int searchBarAppWidgetId = -1;
     public int searchBarSpaceHeightPx;
 
     /** Task stack */
@@ -207,8 +206,6 @@
 
         // Search Bar
         searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-        searchBarAppWidgetId = Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID,
-                -1 /* defaultValue */);
 
         // Task stack
         taskStackScrollDuration =
@@ -279,12 +276,6 @@
         systemInsets.set(insets);
     }
 
-    /** Updates the search bar app widget */
-    public void updateSearchBarAppWidgetId(Context context, int appWidgetId) {
-        searchBarAppWidgetId = appWidgetId;
-        Prefs.putInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, appWidgetId);
-    }
-
     /** Updates the states that need to be re-read whenever we re-initialize. */
     void updateOnReinitialize(Context context, SystemServicesProxy ssp) {
         // Check if the developer options are enabled
@@ -304,11 +295,6 @@
         launchedHasConfigurationChanged = true;
     }
 
-    /** Returns whether the search bar app widget exists. */
-    public boolean hasSearchBarAppWidget() {
-        return searchBarAppWidgetId >= 0;
-    }
-
     /** Returns whether the status bar scrim should be animated when shown for the first time. */
     public boolean shouldAnimateStatusBarScrim() {
         return launchedFromHome;
@@ -335,9 +321,7 @@
      * the system insets.
      */
     public void getAvailableTaskStackBounds(int windowWidth, int windowHeight, int topInset,
-            int rightInset, Rect taskStackBounds) {
-        Rect searchBarBounds = new Rect();
-        getSearchBarBounds(windowWidth, windowHeight, topInset, searchBarBounds);
+            int rightInset, Rect searchBarBounds, Rect taskStackBounds) {
         if (isLandscape && hasTransposedSearchBar) {
             // In landscape, the search bar appears on the left, but we overlay it on top
             taskStackBounds.set(0, topInset, windowWidth - rightInset, windowHeight);
@@ -355,10 +339,6 @@
             Rect searchBarSpaceBounds) {
         // Return empty rects if search is not enabled
         int searchBarSize = searchBarSpaceHeightPx;
-        if (!Constants.DebugFlags.App.EnableSearchLayout || !hasSearchBarAppWidget()) {
-            searchBarSize = 0;
-        }
-
         if (isLandscape && hasTransposedSearchBar) {
             // In landscape, the search bar appears on the left
             searchBarSpaceBounds.set(0, topInset, searchBarSize, windowHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 272d39a..b60c66f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -62,9 +62,11 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsAppWidgetHost;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -527,14 +529,57 @@
     }
 
     /**
-     * Resolves and returns the first Recents widget from the same package as the global
-     * assist activity.
+     * Returns the current search widget id.
      */
-    public AppWidgetProviderInfo resolveSearchAppWidget() {
-        if (mAwm == null) return null;
-        if (mAssistComponent == null) return null;
+    public int getSearchAppWidgetId(Context context) {
+        return Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, -1);
+    }
 
-        // Find the first Recents widget from the same package as the global assist activity
+    /**
+     * Returns the current search widget info, binding a new one if necessary.
+     */
+    public AppWidgetProviderInfo getOrBindSearchAppWidget(Context context, AppWidgetHost host) {
+        int searchWidgetId = Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, -1);
+        AppWidgetProviderInfo searchWidgetInfo = mAwm.getAppWidgetInfo(searchWidgetId);
+        AppWidgetProviderInfo resolvedSearchWidgetInfo = resolveSearchAppWidget();
+
+        // Return the search widget info if it hasn't changed
+        if (searchWidgetInfo != null && resolvedSearchWidgetInfo != null &&
+                searchWidgetInfo.provider.equals(resolvedSearchWidgetInfo.provider)) {
+            if (Prefs.getString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null) == null) {
+                Prefs.putString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE,
+                        searchWidgetInfo.provider.getPackageName());
+            }
+            return searchWidgetInfo;
+        }
+
+        // Delete the old widget
+        if (searchWidgetId != -1) {
+            host.deleteAppWidgetId(searchWidgetId);
+        }
+
+        // And rebind a new search widget
+        if (resolvedSearchWidgetInfo != null) {
+            Pair<Integer, AppWidgetProviderInfo> widgetInfo = bindSearchAppWidget(host,
+                    resolvedSearchWidgetInfo);
+            if (widgetInfo != null) {
+                Prefs.putInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, widgetInfo.first);
+                Prefs.putString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE,
+                        widgetInfo.second.provider.getPackageName());
+                return widgetInfo.second;
+            }
+        }
+
+        // If we fall through here, then there is no resolved search widget, so clear the state
+        Prefs.remove(context, Prefs.Key.SEARCH_APP_WIDGET_ID);
+        Prefs.remove(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE);
+        return null;
+    }
+
+    /**
+     * Returns the first Recents widget from the same package as the global assist activity.
+     */
+    private AppWidgetProviderInfo resolveSearchAppWidget() {
         List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
                 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
         for (AppWidgetProviderInfo info : widgets) {
@@ -548,45 +593,21 @@
     /**
      * Resolves and binds the search app widget that is to appear in the recents.
      */
-    public Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host) {
+    private Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host,
+            AppWidgetProviderInfo resolvedSearchWidgetInfo) {
         if (mAwm == null) return null;
         if (mAssistComponent == null) return null;
 
-        // Find the first Recents widget from the same package as the global assist activity
-        AppWidgetProviderInfo searchWidgetInfo = resolveSearchAppWidget();
-
-        // Return early if there is no search widget
-        if (searchWidgetInfo == null) return null;
-
         // Allocate a new widget id and try and bind the app widget (if that fails, then just skip)
         int searchWidgetId = host.allocateAppWidgetId();
         Bundle opts = new Bundle();
         opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
                 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
-        if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, searchWidgetInfo.provider, opts)) {
+        if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, resolvedSearchWidgetInfo.provider, opts)) {
             host.deleteAppWidgetId(searchWidgetId);
             return null;
         }
-        return new Pair<Integer, AppWidgetProviderInfo>(searchWidgetId, searchWidgetInfo);
-    }
-
-    /**
-     * Returns the app widget info for the specified app widget id.
-     */
-    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
-        if (mAwm == null) return null;
-
-        return mAwm.getAppWidgetInfo(appWidgetId);
-    }
-
-    /**
-     * Destroys the specified app widget.
-     */
-    public void unbindSearchAppWidget(AppWidgetHost host, int appWidgetId) {
-        if (mAwm == null) return;
-
-        // Delete the app widget
-        host.deleteAppWidgetId(appWidgetId);
+        return new Pair<>(searchWidgetId, resolvedSearchWidgetInfo);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index fa97a86e..6cb11b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -287,17 +287,14 @@
 
     /** Adds the search bar */
     public void setSearchBar(RecentsAppWidgetHostView searchBar) {
-        // Create the search bar (and hide it if we have no recent tasks)
-        if (Constants.DebugFlags.App.EnableSearchLayout) {
-            // Remove the previous search bar if one exists
-            if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
-                removeView(mSearchBar);
-            }
-            // Add the new search bar
-            if (searchBar != null) {
-                mSearchBar = searchBar;
-                addView(mSearchBar);
-            }
+        // Remove the previous search bar if one exists
+        if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
+            removeView(mSearchBar);
+        }
+        // Add the new search bar
+        if (searchBar != null) {
+            mSearchBar = searchBar;
+            addView(mSearchBar);
         }
     }
 
@@ -324,8 +321,8 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
         // Get the search bar bounds and measure the search bar layout
+        Rect searchBarSpaceBounds = new Rect();
         if (mSearchBar != null) {
-            Rect searchBarSpaceBounds = new Rect();
             mConfig.getSearchBarBounds(width, height, mConfig.systemInsets.top, searchBarSpaceBounds);
             mSearchBar.measure(
                     MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
@@ -334,7 +331,7 @@
 
         Rect taskStackBounds = new Rect();
         mConfig.getAvailableTaskStackBounds(width, height, mConfig.systemInsets.top,
-                mConfig.systemInsets.right, taskStackBounds);
+                mConfig.systemInsets.right, searchBarSpaceBounds, taskStackBounds);
 
         // Measure each TaskStackView with the full width and height of the window since the
         // transition view is a child of that stack view
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8d20772..3e66907 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -303,6 +303,7 @@
                             try {
                                 ActivityManagerNative.getDefault()
                                         .keyguardWaitingForActivityDrawn();
+                                ActivityManagerNative.getDefault().resumeAppSwitches();
                             } catch (RemoteException e) {
                             }
                         }
@@ -315,7 +316,9 @@
                             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
                                     true /* force */);
                             visibilityChanged(false);
+                            mAssistManager.hideAssist();
                         }
+
                         // Wait for activity start.
                         return handled;
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index f5fdf48..6bcb766 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -213,7 +213,8 @@
             return R.drawable.lockscreen_fingerprint_fp_to_error_state_animation;
         } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
             return R.drawable.lockscreen_fingerprint_error_state_to_fp_animation;
-        } else if (oldState == STATE_FINGERPRINT && newState == STATE_LOCK_OPEN) {
+        } else if (oldState == STATE_FINGERPRINT && newState == STATE_LOCK_OPEN
+                && !mUnlockMethodCache.isCurrentlyInsecure()) {
             return R.drawable.lockscreen_fingerprint_draw_off_animation;
         } else if (newState == STATE_FINGERPRINT && !oldScreenOn && screenOn) {
             return R.drawable.lockscreen_fingerprint_draw_on_animation;
@@ -225,14 +226,14 @@
     private int getState() {
         boolean fingerprintRunning =
                 KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
-        if (mTransientFpError) {
+        if (mUnlockMethodCache.isCurrentlyInsecure()) {
+            return STATE_LOCK_OPEN;
+        } else if (mTransientFpError) {
             return STATE_FINGERPRINT_ERROR;
         } else if (fingerprintRunning) {
             return STATE_FINGERPRINT;
         } else if (mUnlockMethodCache.isFaceUnlockRunning()) {
             return STATE_FACE_UNLOCK;
-        } else if (mUnlockMethodCache.isCurrentlyInsecure()) {
-            return STATE_LOCK_OPEN;
         } else {
             return STATE_LOCKED;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 7f87485..860a6b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -106,6 +106,7 @@
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
@@ -633,7 +634,7 @@
 
         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                 R.layout.super_status_bar, null);
-        mStatusBarWindow.mService = this;
+        mStatusBarWindow.setService(this);
         mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
@@ -676,8 +677,6 @@
             mNotificationPanelDebugText.setVisibility(View.VISIBLE);
         }
 
-        updateShowSearchHoldoff();
-
         try {
             boolean showNav = mWindowManagerService.hasNavigationBar();
             if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
@@ -1013,11 +1012,6 @@
         return mStatusBarWindow;
     }
 
-    public void invokeAssistGesture(boolean vibrate) {
-        mHandler.removeCallbacks(mInvokeAssist);
-        mAssistManager.onGestureInvoked(vibrate);
-    }
-
     public int getStatusBarHeight() {
         if (mNaturalBarHeight < 0) {
             final Resources res = mContext.getResources();
@@ -1044,31 +1038,28 @@
         }
     };
 
-    private int mShowSearchHoldoff = 0;
-    private Runnable mInvokeAssist = new Runnable() {
-        public void run() {
+    private final View.OnLongClickListener mLongPressHomeListener
+            = new View.OnLongClickListener() {
+        @Override
+        public boolean onLongClick(View v) {
+            if (shouldDisableNavbarGestures()) {
+                return false;
+            }
             mAssistManager.prepareBeforeInvocation();
-            invokeAssistGesture(true /* vibrate */);
+            mAssistManager.onGestureInvoked();
             awakenDreams();
             if (mNavigationBarView != null) {
                 mNavigationBarView.abortCurrentGesture();
             }
+            return true;
         }
     };
 
-    View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
+    private final View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
         public boolean onTouch(View v, MotionEvent event) {
             switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    if (!shouldDisableNavbarGestures()) {
-                        mHandler.removeCallbacks(mInvokeAssist);
-                        mHandler.postDelayed(mInvokeAssist, mShowSearchHoldoff);
-                    }
-                    break;
-
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
-                    mHandler.removeCallbacks(mInvokeAssist);
                     awakenDreams();
                     break;
             }
@@ -1096,6 +1087,7 @@
         mNavigationBarView.getBackButton().setLongClickable(true);
         mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
+        mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
         mAssistManager.onConfigurationChanged();
     }
 
@@ -1236,10 +1228,6 @@
         }
     }
 
-    private void updateShowSearchHoldoff() {
-        mShowSearchHoldoff = ViewConfiguration.getLongPressTimeout();
-    }
-
     private void updateNotificationShade() {
         if (mStackScroller == null) return;
 
@@ -2922,7 +2910,6 @@
 
         updateResources();
         repositionNavigationBar();
-        updateShowSearchHoldoff();
         updateRowStates();
         mIconController.updateResources();
         mScreenPinningRequest.onConfigurationChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 634270c..0e22aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -53,7 +53,7 @@
 
     private int mRightInset = 0;
 
-    PhoneStatusBar mService;
+    private PhoneStatusBar mService;
     private final Paint mTransparentSrcPaint = new Paint();
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
@@ -124,14 +124,22 @@
     }
 
     @Override
-    protected void onAttachedToWindow () {
-        super.onAttachedToWindow();
-
+    protected void onFinishInflate() {
+        super.onFinishInflate();
         mStackScrollLayout = (NotificationStackScrollLayout) findViewById(
                 R.id.notification_stack_scroller);
         mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
-        mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
         mBrightnessMirror = findViewById(R.id.brightness_mirror);
+    }
+
+    public void setService(PhoneStatusBar service) {
+        mService = service;
+        mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
+    }
+
+    @Override
+    protected void onAttachedToWindow () {
+        super.onAttachedToWindow();
 
         // We really need to be able to animate while window animations are going on
         // so that activities may be started asynchronously from panel animations
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 6bc51fa..4c99792 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -57,7 +57,7 @@
                 if (isLongClickable()) {
                     // Just an old-fashioned ImageView
                     performLongClick();
-                } else {
+                } else if (mSupportsLongpress) {
                     sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
                     sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
                 }
@@ -92,7 +92,7 @@
         super.onInitializeAccessibilityNodeInfo(info);
         if (mCode != 0) {
             info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
-            if (mSupportsLongpress) {
+            if (mSupportsLongpress || isLongClickable()) {
                 info.addAction(
                         new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
             }
@@ -115,7 +115,7 @@
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
             playSoundEffect(SoundEffectConstants.CLICK);
             return true;
-        } else if (action == ACTION_LONG_CLICK && mCode != 0 && mSupportsLongpress) {
+        } else if (action == ACTION_LONG_CLICK && mCode != 0) {
             sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
             sendEvent(KeyEvent.ACTION_UP, 0);
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
@@ -144,10 +144,8 @@
                     // Provide the same haptic feedback that the system offers for virtual keys.
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                 }
-                if (mSupportsLongpress) {
-                    removeCallbacks(mCheckLongPress);
-                    postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
-                }
+                removeCallbacks(mCheckLongPress);
+                postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                 break;
             case MotionEvent.ACTION_MOVE:
                 x = (int)ev.getX();
@@ -162,9 +160,7 @@
                 if (mCode != 0) {
                     sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
                 }
-                if (mSupportsLongpress) {
-                    removeCallbacks(mCheckLongPress);
-                }
+                removeCallbacks(mCheckLongPress);
                 break;
             case MotionEvent.ACTION_UP:
                 final boolean doIt = isPressed();
@@ -183,9 +179,7 @@
                         performClick();
                     }
                 }
-                if (mSupportsLongpress) {
-                    removeCallbacks(mCheckLongPress);
-                }
+                removeCallbacks(mCheckLongPress);
                 break;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 5700732..f98840b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1898,15 +1898,23 @@
             boolean pinnedAndClosed = row.isPinned() && !mIsExpanded;
             if (!mIsExpanded && !isHeadsUp) {
                 type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
-            } else if (isHeadsUp && (mAddedHeadsUpChildren.contains(row) || pinnedAndClosed)) {
-                if (pinnedAndClosed || shouldHunAppearFromBottom(row)) {
-                    // Our custom add animation
-                    type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR;
-                } else {
-                    // Normal add animation
-                    type = AnimationEvent.ANIMATION_TYPE_ADD;
+            } else {
+                StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
+                if (viewState == null) {
+                    // A view state was never generated for this view, so we don't need to animate
+                    // this. This may happen with notification children.
+                    continue;
                 }
-                onBottom = !pinnedAndClosed;
+                if (isHeadsUp && (mAddedHeadsUpChildren.contains(row) || pinnedAndClosed)) {
+                    if (pinnedAndClosed || shouldHunAppearFromBottom(viewState)) {
+                        // Our custom add animation
+                        type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR;
+                    } else {
+                        // Normal add animation
+                        type = AnimationEvent.ANIMATION_TYPE_ADD;
+                    }
+                    onBottom = !pinnedAndClosed;
+                }
             }
             AnimationEvent event = new AnimationEvent(row, type);
             event.headsUpFromBottom = onBottom;
@@ -1916,8 +1924,7 @@
         mAddedHeadsUpChildren.clear();
     }
 
-    private boolean shouldHunAppearFromBottom(ExpandableNotificationRow row) {
-        StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
+    private boolean shouldHunAppearFromBottom(StackViewState viewState) {
         if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 17e6e3d0..5b8fe89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -893,13 +893,12 @@
                 if (mHostLayout.indexOfChild(changingView) == -1) {
                     // This notification was actually removed, so we need to add it to the overlay
                     mHostLayout.getOverlay().add(changingView);
-                    ViewState viewState = new ViewState();
-                    viewState.initFrom(changingView);
-                    viewState.yTranslation = -changingView.getActualHeight();
+                    mTmpState.initFrom(changingView);
+                    mTmpState.yTranslation = -changingView.getActualHeight();
                     // We temporarily enable Y animations, the real filter will be combined
                     // afterwards anyway
                     mAnimationFilter.animateY = true;
-                    startViewAnimations(changingView, viewState, 0,
+                    startViewAnimations(changingView, mTmpState, 0,
                             ANIMATION_DURATION_HEADS_UP_DISAPPEAR);
                     mChildrenToClearFromOverlay.add(changingView);
                 }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 4fe8fb9..45a7767 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -50,7 +50,9 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -84,6 +86,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -675,13 +678,15 @@
     }
 
     private void handleSystemReady() {
-        resetIfReadyAndConnected();
+        synchronized (mLock) {
+            resetIfReadyAndConnectedLocked();
+        }
 
         // Start scheduling nominally-daily fstrim operations
         MountServiceIdler.scheduleIdlePass(mContext);
     }
 
-    private void resetIfReadyAndConnected() {
+    private void resetIfReadyAndConnectedLocked() {
         Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
                 + ", mDaemonConnected=" + mDaemonConnected);
         if (mSystemReady && mDaemonConnected) {
@@ -780,7 +785,9 @@
     }
 
     private void handleDaemonConnected() {
-        resetIfReadyAndConnected();
+        synchronized (mLock) {
+            resetIfReadyAndConnectedLocked();
+        }
 
         /*
          * Now that we've done our initialization, release
@@ -1600,7 +1607,7 @@
             // reset vold so we bind into new volume into place.
             if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
                 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
-                resetIfReadyAndConnected();
+                resetIfReadyAndConnectedLocked();
             }
 
             writeSettingsLocked();
@@ -1628,7 +1635,7 @@
             }
 
             writeSettingsLocked();
-            resetIfReadyAndConnected();
+            resetIfReadyAndConnectedLocked();
         }
     }
 
@@ -1641,6 +1648,30 @@
     }
 
     @Override
+    public void remountUid(int uid) {
+        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+        waitForReady();
+
+        final int mountExternal = mPms.getMountExternalMode(uid);
+        final String mode;
+        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
+            mode = "default";
+        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
+            mode = "read";
+        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
+            mode = "write";
+        } else {
+            mode = "none";
+        }
+
+        try {
+            mConnector.execute("volume", "remount_uid", uid, mode);
+        } catch (NativeDaemonConnectorException e) {
+            Slog.w(TAG, "Failed to remount UID " + uid + " as " + mode + ": " + e);
+        }
+    }
+
+    @Override
     public void setDebugFlags(int flags, int mask) {
         enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
@@ -1651,7 +1682,7 @@
             }
 
             writeSettingsLocked();
-            resetIfReadyAndConnected();
+            resetIfReadyAndConnectedLocked();
         }
     }
 
@@ -1688,7 +1719,7 @@
                 Slog.d(TAG, "Skipping move to/from primary physical");
                 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
                 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
-                resetIfReadyAndConnected();
+                resetIfReadyAndConnectedLocked();
 
             } else {
                 final VolumeInfo from = Preconditions.checkNotNull(
@@ -2022,7 +2053,7 @@
 
     @Override
     public void finishMediaUpdate() {
-        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("no permission to call finishMediaUpdate()");
         }
         if (mUnmountSignal != null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f031694..7204a6e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,9 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -3209,13 +3211,14 @@
 
             int uid = app.uid;
             int[] gids = null;
-            int mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
+            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
             if (!app.isolated) {
                 int[] permGids = null;
                 try {
                     checkTime(startTime, "startProcess: getting gids from package manager");
-                    permGids = AppGlobals.getPackageManager().getPackageGids(app.info.packageName,
-                            app.userId);
+                    final IPackageManager pm = AppGlobals.getPackageManager();
+                    permGids = pm.getPackageGids(app.info.packageName, app.userId);
+                    mountExternal = pm.getMountExternalMode(uid);
                 } catch (RemoteException e) {
                     throw e.rethrowAsRuntimeException();
                 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f967aef..4ce5c7e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -25,7 +25,6 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
@@ -39,11 +38,13 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
 
+import android.Manifest;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.IActivityContainer;
 import android.app.IActivityContainerCallback;
 import android.app.IActivityManager;
@@ -62,6 +63,7 @@
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
@@ -90,9 +92,11 @@
 import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Slog;
@@ -108,6 +112,7 @@
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityStack.ActivityState;
@@ -170,6 +175,25 @@
 
     private static final String LOCK_TASK_TAG = "Lock-to-App";
 
+    // Activity actions an app cannot start if it uses a permission which is not granted.
+    private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
+            new ArrayMap<>();
+    static {
+        ACTION_TO_RUNTIME_PERMISSION.put(MediaStore.ACTION_IMAGE_CAPTURE,
+                Manifest.permission.CAMERA);
+        ACTION_TO_RUNTIME_PERMISSION.put(MediaStore.ACTION_VIDEO_CAPTURE,
+                Manifest.permission.CAMERA);
+        ACTION_TO_RUNTIME_PERMISSION.put(Intent.ACTION_CALL,
+                Manifest.permission.CALL_PHONE);
+    }
+
+    /** Action not restricted for the calling package. */
+    private static final int ACTION_RESTRICTION_NONE = 0;
+    /** Action restricted for the calling package by not granting a used permission. */
+    private static final int ACTION_RESTRICTION_PERMISSION = 1;
+    /** Action restricted for the calling package by not allowing a used permission's app op. */
+    private static final int ACTION_RESTRICTION_APPOP = 2;
+
     /** Status Bar Service **/
     private IBinder mToken = new Binder();
     private IStatusBarService mStatusBarService;
@@ -1519,14 +1543,23 @@
                 START_ANY_ACTIVITY, callingPid, callingUid);
         final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
                 callingUid, aInfo.applicationInfo.uid, aInfo.exported);
-        if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) {
+        final int actionRestriction = getActionRestrictionForCallingPackage(
+                intent.getAction(), callingPackage, callingPid, callingUid);
+
+        if (startAnyPerm != PERMISSION_GRANTED && (componentPerm != PERMISSION_GRANTED
+                || actionRestriction == ACTION_RESTRICTION_PERMISSION)) {
             if (resultRecord != null) {
                 resultStack.sendActivityResultLocked(-1,
                     resultRecord, resultWho, requestCode,
                     Activity.RESULT_CANCELED, null);
             }
             String msg;
-            if (!aInfo.exported) {
+            if (actionRestriction == ACTION_RESTRICTION_PERMISSION) {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")" + " with revoked permission "
+                        + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
+            } else if (!aInfo.exported) {
                 msg = "Permission Denial: starting " + intent.toString()
                         + " from " + callerApp + " (pid=" + callingPid
                         + ", uid=" + callingUid + ")"
@@ -1541,7 +1574,19 @@
             throw new SecurityException(msg);
         }
 
-        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
+        boolean abort = false;
+
+        if (startAnyPerm != PERMISSION_GRANTED
+                && actionRestriction == ACTION_RESTRICTION_APPOP) {
+            String msg = "Permission Denial: starting " + intent.toString()
+                    + " from " + callerApp + " (pid=" + callingPid
+                    + ", uid=" + callingUid + ")"
+                    + " requires " + aInfo.permission;
+            Slog.w(TAG, msg);
+            abort = true;
+        }
+
+        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                 callingPid, resolvedType, aInfo.applicationInfo);
 
         if (mService.mController != null) {
@@ -1619,6 +1664,48 @@
         return err;
     }
 
+    private int getActionRestrictionForCallingPackage(String action,
+            String callingPackage, int callingPid, int callingUid) {
+        if (action == null) {
+            return ACTION_RESTRICTION_NONE;
+        }
+
+        String permission = ACTION_TO_RUNTIME_PERMISSION.get(action);
+        if (permission == null) {
+            return ACTION_RESTRICTION_NONE;
+        }
+
+        final PackageInfo packageInfo;
+        try {
+            packageInfo = mService.mContext.getPackageManager()
+                    .getPackageInfo(callingPackage, PackageManager.GET_PERMISSIONS);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.i(TAG, "Cannot find package info for " + callingPackage);
+            return ACTION_RESTRICTION_NONE;
+        }
+
+        if (!ArrayUtils.contains(packageInfo.requestedPermissions, permission)) {
+            return ACTION_RESTRICTION_NONE;
+        }
+
+        if (mService.checkPermission(permission, callingPid, callingUid) ==
+                PackageManager.PERMISSION_DENIED) {
+            return ACTION_RESTRICTION_PERMISSION;
+        }
+
+        final int opCode = AppOpsManager.permissionToOpCode(permission);
+        if (opCode == AppOpsManager.OP_NONE) {
+            return ACTION_RESTRICTION_NONE;
+        }
+
+        if (mService.mAppOpsService.noteOperation(opCode, callingUid,
+                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+            return ACTION_RESTRICTION_APPOP;
+        }
+
+        return ACTION_RESTRICTION_NONE;
+    }
+
     ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) {
         final TaskRecord task = r.task;
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4524ff8..d6a7bf93 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -50,6 +50,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.media.AudioAttributes;
@@ -72,6 +73,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.notification.Condition;
@@ -441,6 +443,12 @@
         return true;
     }
 
+    /** Use this to check if a package can post a notification or toast. */
+    private boolean checkNotificationOp(String pkg, int uid) {
+        return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
+                == AppOpsManager.MODE_ALLOWED;
+    }
+
     private static final class ToastRecord
     {
         final int pid;
@@ -1909,6 +1917,26 @@
                     r.dump(pw, "      ", getContext());
                 }
             }
+
+            try {
+                pw.println("\n  Banned Packages:");
+                for(UserInfo user : UserManager.get(getContext()).getUsers()) {
+                    final int userId = user.getUserHandle().getIdentifier();
+                    pw.println("    UserId " + userId);
+                    final PackageManager packageManager = getContext().getPackageManager();
+                    List<PackageInfo> packages = packageManager.getInstalledPackages(0, userId);
+                    final int packageCount = packages.size();
+                    for (int p = 0; p < packageCount; p++) {
+                        final String packageName = packages.get(p).packageName;
+                        final int uid = packageManager.getPackageUid(packageName, userId);
+                        if (!checkNotificationOp(packageName, uid)) {
+                            pw.println("       " + packageName);
+                        }
+                    }
+                }
+            } catch (NameNotFoundException e) {
+                // pass
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index be1afa8..40ff3f4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -54,6 +55,7 @@
 import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
 import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
@@ -196,6 +198,7 @@
 import com.android.internal.content.PackageHelper;
 import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -208,8 +211,8 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
-import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.pm.PermissionsState.PermissionState;
+import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -2562,6 +2565,21 @@
         return null;
     }
 
+    @Override
+    public int getMountExternalMode(int uid) {
+        if (Process.isIsolated(uid)) {
+            return Zygote.MOUNT_EXTERNAL_NONE;
+        } else {
+            if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
+                return Zygote.MOUNT_EXTERNAL_WRITE;
+            } else if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
+                return Zygote.MOUNT_EXTERNAL_READ;
+            } else {
+                return Zygote.MOUNT_EXTERNAL_DEFAULT;
+            }
+        }
+    }
+
     static PermissionInfo generatePermissionInfo(
             BasePermission bp, int flags) {
         if (bp.perm != null) {
@@ -3201,6 +3219,7 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
                 "grantRuntimePermission");
 
+        final int uid;
         final SettingBase sb;
 
         synchronized (mPackages) {
@@ -3216,6 +3235,7 @@
 
             enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
 
+            uid = pkg.applicationInfo.uid;
             sb = (SettingBase) pkg.mExtras;
             if (sb == null) {
                 throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -3245,11 +3265,22 @@
                 } break;
             }
 
-            mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
 
             // Not critical if that is lost - app has to request again.
             mSettings.writeRuntimePermissionsForUserLPr(userId, false);
         }
+
+        if (READ_EXTERNAL_STORAGE.equals(name)
+                || WRITE_EXTERNAL_STORAGE.equals(name)) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final StorageManager storage = mContext.getSystemService(StorageManager.class);
+                storage.remountUid(uid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 06e6a62..e861668 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -211,6 +211,19 @@
             KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
 
     /**
+     * Override the platform's notion of a network operator being considered non roaming.
+     * If true all networks are considered as home network a.k.a non-roaming.  When false,
+     * the 2 pairs of CMDA and GSM roaming/non-roaming arrays are consulted.
+     *
+     * @see KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY
+     * @see KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY
+     * @see KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY
+     * @see KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY
+     */
+    public static final String
+            KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
+
+    /**
      * Flag specifying whether VoLTE should be available for carrier, independent of carrier
      * provisioning. If false: hard disabled. If true: then depends on carrier provisioning,
      * availability, etc.
@@ -407,6 +420,7 @@
         sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
index d44afb0..610f30b 100644
--- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -18,6 +18,11 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
+    <ImageView android:id="@+id/full_screenshot"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible"/>
+
     <com.android.test.voiceinteraction.AssistVisualizer android:id="@+id/assist_visualizer"
             android:layout_width="match_parent"
             android:layout_height="match_parent" />
@@ -30,19 +35,29 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="top"
-            android:orientation="vertical"
+            android:orientation="horizontal"
             android:background="#ffffffff"
             android:elevation="8dp"
             >
+            <ImageView android:id="@+id/screenshot"
+                android:layout_width="wrap_content"
+                android:layout_height="46dp"
+                android:adjustViewBounds="true" />
+            <View android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
+            <Button android:id="@+id/do_tree"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/tree" />
+            <Button android:id="@+id/do_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/text" />
             <Button android:id="@+id/start"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="top|right"
-                android:text="@string/start"
-                />
-            <ImageView android:id="@+id/screenshot"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
+                android:text="@string/start" />
         </LinearLayout>
 
         <LinearLayout android:id="@+id/bottom_content"
@@ -58,26 +73,22 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginBottom="16dp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                />
+                android:textAppearance="?android:attr/textAppearanceMedium" />
 
             <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
                     android:orientation="horizontal">
                 <Button android:id="@+id/confirm"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/confirm"
-                    />
+                    android:text="@string/confirm" />
                 <Button android:id="@+id/complete"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/complete"
-                    />
+                    android:text="@string/complete" />
                 <Button android:id="@+id/abort"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/abort"
-                    />
+                    android:text="@string/abort" />
             </LinearLayout>
 
         </LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index 6289929..4cf4104 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -17,6 +17,8 @@
 <resources>
 
     <string name="start">Start</string>
+    <string name="tree">Tree</string>
+    <string name="text">Text</string>
     <string name="asyncStructure">(Async structure goes here)</string>
     <string name="confirm">Confirm</string>
     <string name="abort">Abort</string>
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 439ace8..339755f 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -20,6 +20,7 @@
 import android.app.assist.AssistStructure;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
@@ -31,10 +32,32 @@
 public class AssistVisualizer extends View {
     static final String TAG = "AssistVisualizer";
 
+    static class TextEntry {
+        final Rect bounds;
+        final int parentLeft, parentTop;
+        final Matrix matrix;
+        final String className;
+        final CharSequence text;
+
+        TextEntry(AssistStructure.ViewNode node, int parentLeft, int parentTop, Matrix matrix) {
+            int left = parentLeft+node.getLeft();
+            int top = parentTop+node.getTop();
+            bounds = new Rect(left, top, left+node.getWidth(), top+node.getHeight());
+            this.parentLeft = parentLeft;
+            this.parentTop = parentTop;
+            this.matrix = new Matrix(matrix);
+            this.className = node.getClassName();
+            this.text = node.getText() != null ? node.getText() : node.getContentDescription();
+        }
+    }
+
     AssistStructure mAssistStructure;
     final Paint mFramePaint = new Paint();
-    final ArrayList<Rect> mTextRects = new ArrayList<>();
+    final Paint mFrameNoTransformPaint = new Paint();
+    final ArrayList<Matrix> mMatrixStack = new ArrayList<>();
+    final ArrayList<TextEntry> mTextRects = new ArrayList<>();
     final int[] mTmpLocation = new int[2];
+    final float[] mTmpMatrixPoint = new float[2];
 
     public AssistVisualizer(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -42,17 +65,26 @@
         mFramePaint.setColor(0xffff0000);
         mFramePaint.setStyle(Paint.Style.STROKE);
         mFramePaint.setStrokeWidth(0);
+        float density = getResources().getDisplayMetrics().density;
+        mFramePaint.setShadowLayer(density, density, density, 0xff000000);
+        mFrameNoTransformPaint.setColor(0xff0000ff);
+        mFrameNoTransformPaint.setStyle(Paint.Style.STROKE);
+        mFrameNoTransformPaint.setStrokeWidth(0);
+        mFrameNoTransformPaint.setShadowLayer(density, density, density, 0xff000000);
     }
 
     public void setAssistStructure(AssistStructure as) {
         mAssistStructure = as;
-        mAssistStructure.dump();
         mTextRects.clear();
         final int N = as.getWindowNodeCount();
         if (N > 0) {
             for (int i=0; i<N; i++) {
                 AssistStructure.WindowNode windowNode = as.getWindowNodeAt(i);
-                buildTextRects(windowNode.getRootViewNode(), windowNode.getLeft(),
+                mMatrixStack.clear();
+                Matrix matrix = new Matrix();
+                matrix.setTranslate(windowNode.getLeft(), windowNode.getTop());
+                mMatrixStack.add(matrix);
+                buildTextRects(windowNode.getRootViewNode(), 0, windowNode.getLeft(),
                         windowNode.getTop());
             }
         }
@@ -60,31 +92,62 @@
         invalidate();
     }
 
+    public void logTree() {
+        if (mAssistStructure != null) {
+            mAssistStructure.dump();
+        }
+    }
+
+    public void logText() {
+        final int N = mTextRects.size();
+        for (int i=0; i<N; i++) {
+            TextEntry te = mTextRects.get(i);
+            Log.d(TAG, "View " + te.className + " " + te.bounds.toShortString()
+                    + " in " + te.parentLeft + "," + te.parentTop
+                    + " matrix=" + te.matrix.toShortString() + ": "
+                    + te.text);
+        }
+    }
+
     public void clearAssistData() {
         mAssistStructure = null;
         mTextRects.clear();
     }
 
-    void buildTextRects(AssistStructure.ViewNode root, int parentLeft, int parentTop) {
+    void buildTextRects(AssistStructure.ViewNode root, int matrixStackIndex,
+            int parentLeft, int parentTop) {
         if (root.getVisibility() != View.VISIBLE) {
             return;
         }
-        int left = parentLeft+root.getLeft();
-        int top = parentTop+root.getTop();
+        Matrix parentMatrix = mMatrixStack.get(matrixStackIndex);
+        matrixStackIndex++;
+        Matrix matrix;
+        if (mMatrixStack.size() > matrixStackIndex) {
+            matrix = mMatrixStack.get(matrixStackIndex);
+            matrix.set(parentMatrix);
+        } else {
+            matrix = new Matrix(parentMatrix);
+            mMatrixStack.add(matrix);
+        }
+        matrix.preTranslate(root.getLeft(), root.getTop());
+        int left = parentLeft + root.getLeft();
+        int top = parentTop + root.getTop();
+        Matrix transform = root.getTransformation();
+        if (transform != null) {
+            matrix.preConcat(transform);
+        }
         if (root.getText() != null || root.getContentDescription() != null) {
-            Rect r = new Rect(left, top, left+root.getWidth(), top+root.getHeight());
-            Log.d(TAG, "View " + root.getClassName() + " " + left + "," + top + " tr "
-                    + r.toShortString() + ": "
-                    + (root.getText() != null ? root.getText() : root.getContentDescription()));
-            mTextRects.add(r);
+            TextEntry te = new TextEntry(root, parentLeft, parentTop, matrix);
+            mTextRects.add(te);
         }
         final int N = root.getChildCount();
         if (N > 0) {
             left -= root.getScrollX();
             top -= root.getScrollY();
+            matrix.preTranslate(-root.getScrollX(), -root.getScrollY());
             for (int i=0; i<N; i++) {
                 AssistStructure.ViewNode child = root.getChildAt(i);
-                buildTextRects(child, left, top);
+                buildTextRects(child, matrixStackIndex, left, top);
             }
         }
     }
@@ -96,9 +159,19 @@
         final int N = mTextRects.size();
         Log.d(TAG, "Drawing text rects in " + this + ": found " + mTextRects.size());
         for (int i=0; i<N; i++) {
-            Rect r = mTextRects.get(i);
-            canvas.drawRect(r.left-mTmpLocation[0], r.top-mTmpLocation[1],
-                    r.right-mTmpLocation[0], r.bottom-mTmpLocation[1], mFramePaint);
+            TextEntry te = mTextRects.get(i);
+            canvas.drawRect(te.bounds.left - mTmpLocation[0], te.bounds.top - mTmpLocation[1],
+                    te.bounds.right - mTmpLocation[0], te.bounds.bottom - mTmpLocation[1],
+                    mFrameNoTransformPaint);
+        }
+        for (int i=0; i<N; i++) {
+            TextEntry te = mTextRects.get(i);
+            canvas.save();
+            canvas.translate(-mTmpLocation[0], -mTmpLocation[1]);
+            canvas.concat(te.matrix);
+            canvas.drawRect(0, 0, te.bounds.right - te.bounds.left, te.bounds.bottom - te.bounds.top,
+                    mFramePaint);
+            canvas.restore();
         }
     }
 }
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 90a781c..97c1e85 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -42,8 +42,11 @@
     View mTopContent;
     View mBottomContent;
     TextView mText;
+    Button mTreeButton;
+    Button mTextButton;
     Button mStartButton;
     ImageView mScreenshot;
+    ImageView mFullScreenshot;
     Button mConfirmButton;
     Button mCompleteButton;
     Button mAbortButton;
@@ -110,9 +113,15 @@
         mTopContent = mContentView.findViewById(R.id.top_content);
         mBottomContent = mContentView.findViewById(R.id.bottom_content);
         mText = (TextView)mContentView.findViewById(R.id.text);
+        mTreeButton = (Button)mContentView.findViewById(R.id.do_tree);
+        mTreeButton.setOnClickListener(this);
+        mTextButton = (Button)mContentView.findViewById(R.id.do_text);
+        mTextButton.setOnClickListener(this);
         mStartButton = (Button)mContentView.findViewById(R.id.start);
         mStartButton.setOnClickListener(this);
         mScreenshot = (ImageView)mContentView.findViewById(R.id.screenshot);
+        mScreenshot.setOnClickListener(this);
+        mFullScreenshot = (ImageView)mContentView.findViewById(R.id.full_screenshot);
         mConfirmButton = (Button)mContentView.findViewById(R.id.confirm);
         mConfirmButton.setOnClickListener(this);
         mCompleteButton = (Button)mContentView.findViewById(R.id.complete);
@@ -156,8 +165,10 @@
             mScreenshot.setAdjustViewBounds(true);
             mScreenshot.setMaxWidth(screenshot.getWidth()/3);
             mScreenshot.setMaxHeight(screenshot.getHeight()/3);
+            mFullScreenshot.setImageBitmap(screenshot);
         } else {
             mScreenshot.setImageDrawable(null);
+            mFullScreenshot.setImageDrawable(null);
         }
     }
 
@@ -183,7 +194,15 @@
     }
 
     public void onClick(View v) {
-        if (v == mStartButton) {
+        if (v == mTreeButton) {
+            if (mAssistVisualizer != null) {
+                mAssistVisualizer.logTree();
+            }
+        } else if (v == mTextButton) {
+            if (mAssistVisualizer != null) {
+                mAssistVisualizer.logText();
+            }
+        } else if (v == mStartButton) {
             mState = STATE_LAUNCHING;
             updateState();
             startVoiceActivity(mStartIntent);
@@ -219,9 +238,15 @@
         } else if (v == mAbortButton) {
             mPendingRequest.sendAbortVoiceResult(null);
             mPendingRequest = null;
-        } else if (v== mCompleteButton) {
+        } else if (v == mCompleteButton) {
             mPendingRequest.sendCompleteVoiceResult(null);
             mPendingRequest = null;
+        } else if (v == mScreenshot) {
+            if (mFullScreenshot.getVisibility() != View.VISIBLE) {
+                mFullScreenshot.setVisibility(View.VISIBLE);
+            } else {
+                mFullScreenshot.setVisibility(View.INVISIBLE);
+            }
         }
         updateState();
     }
diff --git a/tests/WebViewTests/Android.mk b/tests/WebViewTests/Android.mk
deleted file mode 100644
index b118845..0000000
--- a/tests/WebViewTests/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# Copyright (C) 2011 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_PACKAGE_NAME := WebViewTests
-
-include $(BUILD_PACKAGE)
diff --git a/tests/WebViewTests/AndroidManifest.xml b/tests/WebViewTests/AndroidManifest.xml
deleted file mode 100644
index 8b080c1..0000000
--- a/tests/WebViewTests/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2011 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.webviewtests">
-    <application>
-        <uses-library android:name="android.test.runner" />
-        <activity android:name="WebViewStubActivity" android:label="WebViewStubActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.TEST" />
-            </intent-filter>
-        </activity>
-    </application>
-
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="com.android.webviewtests"
-                     android:label="Tests for android.webkit.WebView" />
-</manifest>
diff --git a/tests/WebViewTests/res/layout/webview_layout.xml b/tests/WebViewTests/res/layout/webview_layout.xml
deleted file mode 100644
index d266d21..0000000
--- a/tests/WebViewTests/res/layout/webview_layout.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <WebView android:id="@+id/web_page"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-</LinearLayout>
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayCoercionTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayCoercionTest.java
deleted file mode 100644
index c2bbdf5..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayCoercionTest.java
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**
- * Part of the test suite for the WebView's Java Bridge. This class tests that
- * we correctly convert JavaScript arrays to Java arrays when passing them to
- * the methods of injected Java objects.
- *
- * The conversions should follow
- * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
- * which the implementation differs from the spec are marked with
- * LIVECONNECT_COMPLIANCE.
- * FIXME: Consider making our implementation more compliant, if it will not
- * break backwards-compatibility. See b/4408210.
- *
- * To run this test ...
- *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeArrayCoercionTest \
- *     com.android.webviewtests/android.test.InstrumentationTestRunner
- */
-
-package com.android.webviewtests;
-
-public class JavaBridgeArrayCoercionTest extends JavaBridgeTestBase {
-    private class TestObject extends Controller {
-        private Object mObjectInstance;
-        private CustomType mCustomTypeInstance;
-
-        private boolean[] mBooleanArray;
-        private byte[] mByteArray;
-        private char[] mCharArray;
-        private short[] mShortArray;
-        private int[] mIntArray;
-        private long[] mLongArray;
-        private float[] mFloatArray;
-        private double[] mDoubleArray;
-        private String[] mStringArray;
-        private Object[] mObjectArray;
-        private CustomType[] mCustomTypeArray;
-
-        public TestObject() {
-            mObjectInstance = new Object();
-            mCustomTypeInstance = new CustomType();
-        }
-
-        public Object getObjectInstance() {
-            return mObjectInstance;
-        }
-        public CustomType getCustomTypeInstance() {
-            return mCustomTypeInstance;
-        }
-
-        public synchronized void setBooleanArray(boolean[] x) {
-            mBooleanArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setByteArray(byte[] x) {
-            mByteArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setCharArray(char[] x) {
-            mCharArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setShortArray(short[] x) {
-            mShortArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setIntArray(int[] x) {
-            mIntArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setLongArray(long[] x) {
-            mLongArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setFloatArray(float[] x) {
-            mFloatArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setDoubleArray(double[] x) {
-            mDoubleArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setStringArray(String[] x) {
-            mStringArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setObjectArray(Object[] x) {
-            mObjectArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setCustomTypeArray(CustomType[] x) {
-            mCustomTypeArray = x;
-            notifyResultIsReady();
-        }
-
-        public synchronized boolean[] waitForBooleanArray() {
-            waitForResult();
-            return mBooleanArray;
-        }
-        public synchronized byte[] waitForByteArray() {
-            waitForResult();
-            return mByteArray;
-        }
-        public synchronized char[] waitForCharArray() {
-            waitForResult();
-            return mCharArray;
-        }
-        public synchronized short[] waitForShortArray() {
-            waitForResult();
-            return mShortArray;
-        }
-        public synchronized int[] waitForIntArray() {
-            waitForResult();
-            return mIntArray;
-        }
-        public synchronized long[] waitForLongArray() {
-            waitForResult();
-            return mLongArray;
-        }
-        public synchronized float[] waitForFloatArray() {
-            waitForResult();
-            return mFloatArray;
-        }
-        public synchronized double[] waitForDoubleArray() {
-            waitForResult();
-            return mDoubleArray;
-        }
-        public synchronized String[] waitForStringArray() {
-            waitForResult();
-            return mStringArray;
-        }
-        public synchronized Object[] waitForObjectArray() {
-            waitForResult();
-            return mObjectArray;
-        }
-        public synchronized CustomType[] waitForCustomTypeArray() {
-            waitForResult();
-            return mCustomTypeArray;
-        }
-    }
-
-    // Two custom types used when testing passing objects.
-    private class CustomType {
-    }
-
-    private TestObject mTestObject;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestObject = new TestObject();
-        setUpWebView(mTestObject, "testObject");
-    }
-
-    // Note that all tests use a single element array for simplicity. We test
-    // multiple elements elsewhere.
-
-    // Test passing an array of JavaScript numbers in the int32 range to a
-    // method which takes a Java array.
-    public void testPassNumberInt32() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([0]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-        // LIVECONNECT_COMPLIANCE: Should convert to boolean.
-        executeJavaScript("testObject.setBooleanArray([42]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        executeJavaScript("testObject.setByteArray([42]);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
-        executeJavaScript("testObject.setCharArray([42]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        executeJavaScript("testObject.setShortArray([42]);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
-
-        executeJavaScript("testObject.setIntArray([42]);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
-
-        executeJavaScript("testObject.setLongArray([42]);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
-
-        executeJavaScript("testObject.setFloatArray([42]);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
-
-        executeJavaScript("testObject.setDoubleArray([42]);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([42]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([42]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([42]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript numbers in the double range to a
-    // method which takes a Java array.
-    public void testPassNumberDouble() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should convert to boolean.
-        executeJavaScript("testObject.setBooleanArray([42.1]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        executeJavaScript("testObject.setByteArray([42.1]);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
-        executeJavaScript("testObject.setCharArray([42.1]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        executeJavaScript("testObject.setShortArray([42.1]);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
-
-        executeJavaScript("testObject.setIntArray([42.1]);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
-
-        executeJavaScript("testObject.setLongArray([42.1]);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
-
-        executeJavaScript("testObject.setFloatArray([42.1]);");
-        assertEquals(42.1f, mTestObject.waitForFloatArray()[0]);
-
-        executeJavaScript("testObject.setDoubleArray([42.1]);");
-        assertEquals(42.1, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([42.1]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([42.1]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([42.1]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript NaN values to a method which takes a
-    // Java array.
-    public void testPassNumberNaN() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([Number.NaN]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        executeJavaScript("testObject.setByteArray([Number.NaN]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-
-        executeJavaScript("testObject.setCharArray([Number.NaN]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        executeJavaScript("testObject.setShortArray([Number.NaN]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-
-        executeJavaScript("testObject.setIntArray([Number.NaN]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-
-        executeJavaScript("testObject.setLongArray([Number.NaN]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-
-        executeJavaScript("testObject.setFloatArray([Number.NaN]);");
-        assertEquals(Float.NaN, mTestObject.waitForFloatArray()[0]);
-
-        executeJavaScript("testObject.setDoubleArray([Number.NaN]);");
-        assertEquals(Double.NaN, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([Number.NaN]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([Number.NaN]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([Number.NaN]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript infinity values to a method which
-    // takes a Java array.
-    public void testPassNumberInfinity() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([Infinity]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        executeJavaScript("testObject.setByteArray([Infinity]);");
-        assertEquals(-1, mTestObject.waitForByteArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should convert to maximum numeric char value.
-        executeJavaScript("testObject.setCharArray([Infinity]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        executeJavaScript("testObject.setShortArray([Infinity]);");
-        assertEquals(-1, mTestObject.waitForShortArray()[0]);
-
-        executeJavaScript("testObject.setIntArray([Infinity]);");
-        assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE.
-        executeJavaScript("testObject.setLongArray([Infinity]);");
-        assertEquals(-1L, mTestObject.waitForLongArray()[0]);
-
-        executeJavaScript("testObject.setFloatArray([Infinity]);");
-        assertEquals(Float.POSITIVE_INFINITY, mTestObject.waitForFloatArray()[0]);
-
-        executeJavaScript("testObject.setDoubleArray([Infinity]);");
-        assertEquals(Double.POSITIVE_INFINITY, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([Infinity]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([Infinity]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([Infinity]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript boolean values to a method which
-    // takes a Java array.
-    public void testPassBoolean() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([true]);");
-        assertTrue(mTestObject.waitForBooleanArray()[0]);
-        executeJavaScript("testObject.setBooleanArray([false]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setByteArray([true]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-        executeJavaScript("testObject.setByteArray([false]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should convert to numeric char value 1.
-        executeJavaScript("testObject.setCharArray([true]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-        executeJavaScript("testObject.setCharArray([false]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setShortArray([true]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-        executeJavaScript("testObject.setShortArray([false]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setIntArray([true]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-        executeJavaScript("testObject.setIntArray([false]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setLongArray([true]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-        executeJavaScript("testObject.setLongArray([false]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setFloatArray([true]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-        executeJavaScript("testObject.setFloatArray([false]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setDoubleArray([true]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-        executeJavaScript("testObject.setDoubleArray([false]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([true]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([true]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([true]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript strings to a method which takes a
-    // Java array.
-    public void testPassString() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Non-empty string should convert to true.
-        executeJavaScript("testObject.setBooleanArray([\"+042.10\"]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setByteArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should decode and convert to numeric char value.
-        executeJavaScript("testObject.setCharArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForCharArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setShortArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setIntArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setLongArray([\"+042.10\"]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setFloatArray([\"+042.10\"]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setDoubleArray([\"+042.10\"]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([\"+042.10\"]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        executeJavaScript("testObject.setStringArray([\"+042.10\"]);");
-        assertEquals("+042.10", mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([\"+042.10\"]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript objects to a method which takes a
-    // Java array.
-    public void testPassJavaScriptObject() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanArray([{foo: 42}]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteArray([{foo: 42}]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharArray([{foo: 42}]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortArray([{foo: 42}]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray([{foo: 42}]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongArray([{foo: 42}]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatArray([{foo: 42}]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleArray([{foo: 42}]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setObjectArray([{foo: 42}]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringArray([{foo: 42}]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([{foo: 42}]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of Java objects to a method which takes a Java
-    // array.
-    public void testPassJavaObject() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanArray([testObject.getObjectInstance()]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteArray([testObject.getObjectInstance()]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharArray([testObject.getObjectInstance()]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortArray([testObject.getObjectInstance()]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray([testObject.getObjectInstance()]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongArray([testObject.getObjectInstance()]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatArray([testObject.getObjectInstance()]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleArray([testObject.getObjectInstance()]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create an array and pass Java object.
-        executeJavaScript("testObject.setObjectArray([testObject.getObjectInstance()]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringArray([testObject.getObjectInstance()]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and pass Java object.
-        executeJavaScript("testObject.setCustomTypeArray([testObject.getObjectInstance()]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-        executeJavaScript("testObject.setCustomTypeArray([testObject.getCustomTypeInstance()]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript null values to a method which takes
-    // a Java array.
-    public void testPassNull() throws Throwable {
-        executeJavaScript("testObject.setByteArray([null]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-
-        executeJavaScript("testObject.setCharArray([null]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-
-        executeJavaScript("testObject.setShortArray([null]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-
-        executeJavaScript("testObject.setIntArray([null]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-
-        executeJavaScript("testObject.setLongArray([null]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-
-        executeJavaScript("testObject.setFloatArray([null]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-
-        executeJavaScript("testObject.setDoubleArray([null]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-
-        executeJavaScript("testObject.setBooleanArray([null]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setObjectArray([null]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        executeJavaScript("testObject.setStringArray([null]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setCustomTypeArray([null]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-
-    // Test passing an array of JavaScript undefined values to a method which
-    // takes a Java array.
-    public void testPassUndefined() throws Throwable {
-        executeJavaScript("testObject.setByteArray([undefined]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-
-        executeJavaScript("testObject.setCharArray([undefined]);");
-        assertEquals(0, mTestObject.waitForCharArray()[0]);
-
-        executeJavaScript("testObject.setShortArray([undefined]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-
-        executeJavaScript("testObject.setIntArray([undefined]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-
-        executeJavaScript("testObject.setLongArray([undefined]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-
-        executeJavaScript("testObject.setFloatArray([undefined]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-
-        executeJavaScript("testObject.setDoubleArray([undefined]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-
-        executeJavaScript("testObject.setBooleanArray([undefined]);");
-        assertEquals(false, mTestObject.waitForBooleanArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setObjectArray([undefined]);");
-        assertNull(mTestObject.waitForObjectArray());
-
-        executeJavaScript("testObject.setStringArray([undefined]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
-
-        // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setCustomTypeArray([undefined]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayTest.java
deleted file mode 100644
index 2fd42a74d..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**
- * Part of the test suite for the WebView's Java Bridge. This class tests the
- * general use of arrays.
- *
- * The conversions should follow
- * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
- * which the implementation differs from the spec are marked with
- * LIVECONNECT_COMPLIANCE.
- * FIXME: Consider making our implementation more compliant, if it will not
- * break backwards-compatibility. See b/4408210.
- *
- * To run this test ...
- *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeArrayTest \
- *     com.android.webviewtests/android.test.InstrumentationTestRunner
- */
-
-package com.android.webviewtests;
-
-public class JavaBridgeArrayTest extends JavaBridgeTestBase {
-    private class TestObject extends Controller {
-        private boolean mBooleanValue;
-        private int mIntValue;
-        private String mStringValue;
-
-        private int[] mIntArray;
-        private int[][] mIntIntArray;
-
-        private boolean mWasArrayMethodCalled;
-
-        public synchronized void setBooleanValue(boolean x) {
-            mBooleanValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setIntValue(int x) {
-            mIntValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setStringValue(String x) {
-            mStringValue = x;
-            notifyResultIsReady();
-        }
-
-        public synchronized boolean waitForBooleanValue() {
-            waitForResult();
-            return mBooleanValue;
-        }
-        public synchronized int waitForIntValue() {
-            waitForResult();
-            return mIntValue;
-        }
-        public synchronized String waitForStringValue() {
-            waitForResult();
-            return mStringValue;
-        }
-
-        public synchronized void setIntArray(int[] x) {
-            mIntArray = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setIntIntArray(int[][] x) {
-            mIntIntArray = x;
-            notifyResultIsReady();
-        }
-
-        public synchronized int[] waitForIntArray() {
-            waitForResult();
-            return mIntArray;
-        }
-        public synchronized int[][] waitForIntIntArray() {
-            waitForResult();
-            return mIntIntArray;
-        }
-
-        public synchronized int[] arrayMethod() {
-            mWasArrayMethodCalled = true;
-            return new int[] {42, 43, 44};
-        }
-
-        public synchronized boolean wasArrayMethodCalled() {
-            return mWasArrayMethodCalled;
-        }
-    }
-
-    private TestObject mTestObject;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestObject = new TestObject();
-        setUpWebView(mTestObject, "testObject");
-    }
-
-    public void testArrayLength() throws Throwable {
-        executeJavaScript("testObject.setIntArray([42, 43, 44]);");
-        int[] result = mTestObject.waitForIntArray();
-        assertEquals(3, result.length);
-        assertEquals(42, result[0]);
-        assertEquals(43, result[1]);
-        assertEquals(44, result[2]);
-    }
-
-    public void testPassNull() throws Throwable {
-        executeJavaScript("testObject.setIntArray(null);");
-        assertNull(mTestObject.waitForIntArray());
-    }
-
-    public void testPassUndefined() throws Throwable {
-        executeJavaScript("testObject.setIntArray(undefined);");
-        assertNull(mTestObject.waitForIntArray());
-    }
-
-    public void testPassEmptyArray() throws Throwable {
-        executeJavaScript("testObject.setIntArray([]);");
-        assertEquals(0, mTestObject.waitForIntArray().length);
-    }
-
-    // Note that this requires being able to pass a string from JavaScript to
-    // Java.
-    public void testPassArrayToStringMethod() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should call toString() on array.
-        executeJavaScript("testObject.setStringValue([42, 42, 42]);");
-        assertEquals("undefined", mTestObject.waitForStringValue());
-    }
-
-    // Note that this requires being able to pass an integer from JavaScript to
-    // Java.
-    public void testPassArrayToNonStringNonArrayMethod() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception.
-        executeJavaScript("testObject.setIntValue([42, 42, 42]);");
-        assertEquals(0, mTestObject.waitForIntValue());
-    }
-
-    public void testPassNonArrayToArrayMethod() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception.
-        executeJavaScript("testObject.setIntArray(42);");
-        assertNull(mTestObject.waitForIntArray());
-    }
-
-    public void testObjectWithLengthProperty() throws Throwable {
-        executeJavaScript("testObject.setIntArray({length: 3, 1: 42});");
-        int[] result = mTestObject.waitForIntArray();
-        assertEquals(3, result.length);
-        assertEquals(0, result[0]);
-        assertEquals(42, result[1]);
-        assertEquals(0, result[2]);
-    }
-
-    public void testNonNumericLengthProperty() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
-        // should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray({length: \"foo\"});");
-        assertNull(mTestObject.waitForIntArray());
-    }
-
-    public void testLengthOutOfBounds() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
-        // should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray({length: -1});");
-        assertNull(mTestObject.waitForIntArray());
-
-        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
-        // should raise a JavaScript exception.
-        long length = (long)Integer.MAX_VALUE + 1L;
-        executeJavaScript("testObject.setIntArray({length: " + length + "});");
-        assertNull(mTestObject.waitForIntArray());
-
-        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
-        // should raise a JavaScript exception.
-        length = (long)Integer.MAX_VALUE + 1L - (long)Integer.MIN_VALUE + 1L;
-        executeJavaScript("testObject.setIntArray({length: " + length + "});");
-        assertNull(mTestObject.waitForIntArray());
-    }
-
-    public void testSparseArray() throws Throwable {
-        executeJavaScript("var x = [42, 43]; x[3] = 45; testObject.setIntArray(x);");
-        int[] result = mTestObject.waitForIntArray();
-        assertEquals(4, result.length);
-        assertEquals(42, result[0]);
-        assertEquals(43, result[1]);
-        assertEquals(0, result[2]);
-        assertEquals(45, result[3]);
-    }
-
-    // Note that this requires being able to pass a boolean from JavaScript to
-    // Java.
-    public void testMethodReturningArrayNotCalled() throws Throwable {
-        // We don't invoke methods which return arrays, but note that no
-        // exception is raised.
-        // LIVECONNECT_COMPLIANCE: Should call method and convert result to
-        // JavaScript array.
-        executeJavaScript("testObject.setBooleanValue(undefined === testObject.arrayMethod())");
-        assertTrue(mTestObject.waitForBooleanValue());
-        assertFalse(mTestObject.wasArrayMethodCalled());
-    }
-
-    public void testMultiDimensionalArrayMethod() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays.
-        executeJavaScript("testObject.setIntIntArray([ [42, 43], [44, 45] ]);");
-        assertNull(mTestObject.waitForIntIntArray());
-    }
-
-    public void testPassMultiDimensionalArray() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays.
-        executeJavaScript("testObject.setIntArray([ [42, 43], [44, 45] ]);");
-        int[] result = mTestObject.waitForIntArray();
-        assertEquals(2, result.length);
-        assertEquals(0, result[0]);
-        assertEquals(0, result[1]);
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java
deleted file mode 100644
index 1ecccf6..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**
- * Part of the test suite for the WebView's Java Bridge. Tests a number of features including ...
- * - The type of injected objects
- * - The type of their methods
- * - Replacing objects
- * - Removing objects
- * - Access control
- * - Calling methods on returned objects
- * - Multiply injected objects
- * - Threading
- * - Inheritance
- *
- * To run this test ...
- *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeBasicsTest \
- *     com.android.webviewtests/android.test.InstrumentationTestRunner
- */
-
-package com.android.webviewtests;
-
-public class JavaBridgeBasicsTest extends JavaBridgeTestBase {
-    private class TestController extends Controller {
-        private int mIntValue;
-        private long mLongValue;
-        private String mStringValue;
-        private boolean mBooleanValue;
-
-        public synchronized void setIntValue(int x) {
-            mIntValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setLongValue(long x) {
-            mLongValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setStringValue(String x) {
-            mStringValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setBooleanValue(boolean x) {
-            mBooleanValue = x;
-            notifyResultIsReady();
-        }
-
-        public synchronized int waitForIntValue() {
-            waitForResult();
-            return mIntValue;
-        }
-        public synchronized long waitForLongValue() {
-            waitForResult();
-            return mLongValue;
-        }
-        public synchronized String waitForStringValue() {
-            waitForResult();
-            return mStringValue;
-        }
-        public synchronized boolean waitForBooleanValue() {
-            waitForResult();
-            return mBooleanValue;
-        }
-    }
-
-    private static class ObjectWithStaticMethod {
-        public static String staticMethod() {
-            return "foo";
-        }
-    }
-
-    TestController mTestController;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestController = new TestController();
-        setUpWebView(mTestController, "testController");
-    }
-
-    // Note that this requires that we can pass a JavaScript string to Java.
-    protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
-        executeJavaScript("testController.setStringValue(" + script + ");");
-        return mTestController.waitForStringValue();
-    }
-
-    protected void injectObjectAndReload(final Object object, final String name) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().addJavascriptInterface(object, name);
-                getWebView().reload();
-            }
-        });
-        mWebViewClient.waitForOnPageFinished();
-    }
-
-    // Note that this requires that we can pass a JavaScript boolean to Java.
-    private void assertRaisesException(String script) throws Throwable {
-        executeJavaScript("try {" +
-                          script + ";" +
-                          "  testController.setBooleanValue(false);" +
-                          "} catch (exception) {" +
-                          "  testController.setBooleanValue(true);" +
-                          "}");
-        assertTrue(mTestController.waitForBooleanValue());
-    }
-
-    public void testTypeOfInjectedObject() throws Throwable {
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
-    }
-
-    public void testAdditionNotReflectedUntilReload() throws Throwable {
-        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().addJavascriptInterface(new Object(), "testObject");
-            }
-        });
-        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().reload();
-            }
-        });
-        mWebViewClient.waitForOnPageFinished();
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
-    }
-
-    public void testRemovalNotReflectedUntilReload() throws Throwable {
-        injectObjectAndReload(new Object(), "testObject");
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().removeJavascriptInterface("testObject");
-            }
-        });
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().reload();
-            }
-        });
-        mWebViewClient.waitForOnPageFinished();
-        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
-    }
-
-    public void testRemoveObjectNotAdded() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().removeJavascriptInterface("foo");
-                getWebView().reload();
-            }
-        });
-        mWebViewClient.waitForOnPageFinished();
-        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof foo"));
-    }
-
-    public void testTypeOfMethod() throws Throwable {
-        assertEquals("function",
-                executeJavaScriptAndGetStringResult("typeof testController.setStringValue"));
-    }
-
-    public void testTypeOfInvalidMethod() throws Throwable {
-        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testController.foo"));
-    }
-
-    public void testCallingInvalidMethodRaisesException() throws Throwable {
-        assertRaisesException("testController.foo()");
-    }
-
-    public void testUncaughtJavaExceptionRaisesJavaException() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public void method() { throw new RuntimeException("foo"); }
-        }, "testObject");
-        assertRaisesException("testObject.method()");
-    }
-
-    // Note that this requires that we can pass a JavaScript string to Java.
-    public void testTypeOfStaticMethod() throws Throwable {
-        injectObjectAndReload(new ObjectWithStaticMethod(), "testObject");
-        executeJavaScript("testController.setStringValue(typeof testObject.staticMethod)");
-        assertEquals("function", mTestController.waitForStringValue());
-    }
-
-    // Note that this requires that we can pass a JavaScript string to Java.
-    public void testCallStaticMethod() throws Throwable {
-        injectObjectAndReload(new ObjectWithStaticMethod(), "testObject");
-        executeJavaScript("testController.setStringValue(testObject.staticMethod())");
-        assertEquals("foo", mTestController.waitForStringValue());
-    }
-
-    public void testPrivateMethodNotExposed() throws Throwable {
-        injectObjectAndReload(new Object() {
-            private void method() {}
-        }, "testObject");
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.method"));
-    }
-
-    public void testReplaceInjectedObject() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public void method() { mTestController.setStringValue("object 1"); }
-        }, "testObject");
-        executeJavaScript("testObject.method()");
-        assertEquals("object 1", mTestController.waitForStringValue());
-
-        injectObjectAndReload(new Object() {
-            public void method() { mTestController.setStringValue("object 2"); }
-        }, "testObject");
-        executeJavaScript("testObject.method()");
-        assertEquals("object 2", mTestController.waitForStringValue());
-    }
-
-    public void testInjectNullObjectIsIgnored() throws Throwable {
-        injectObjectAndReload(null, "testObject");
-        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
-    }
-
-    public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwable {
-        injectObjectAndReload(new Object(), "testObject");
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
-        injectObjectAndReload(null, "testObject");
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
-    }
-
-    public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public void method() { mTestController.setStringValue("0 args"); }
-            public void method(int x) { mTestController.setStringValue("1 arg"); }
-            public void method(int x, int y) { mTestController.setStringValue("2 args"); }
-        }, "testObject");
-        executeJavaScript("testObject.method()");
-        assertEquals("0 args", mTestController.waitForStringValue());
-        executeJavaScript("testObject.method(42)");
-        assertEquals("1 arg", mTestController.waitForStringValue());
-        executeJavaScript("testObject.method(null)");
-        assertEquals("1 arg", mTestController.waitForStringValue());
-        executeJavaScript("testObject.method(undefined)");
-        assertEquals("1 arg", mTestController.waitForStringValue());
-        executeJavaScript("testObject.method(42, 42)");
-        assertEquals("2 args", mTestController.waitForStringValue());
-    }
-
-    public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws Throwable {
-        assertRaisesException("testController.setIntValue()");
-        assertRaisesException("testController.setIntValue(42, 42)");
-    }
-
-    public void testObjectPersistsAcrossPageLoads() throws Throwable {
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().reload();
-            }
-        });
-        mWebViewClient.waitForOnPageFinished();
-        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
-    }
-
-    public void testSameObjectInjectedMultipleTimes() throws Throwable {
-        class TestObject {
-            private int mNumMethodInvocations;
-            public void method() { mTestController.setIntValue(++mNumMethodInvocations); }
-        }
-        final TestObject testObject = new TestObject();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().addJavascriptInterface(testObject, "testObject1");
-                getWebView().addJavascriptInterface(testObject, "testObject2");
-                getWebView().reload();
-            }
-        });
-        mWebViewClient.waitForOnPageFinished();
-        executeJavaScript("testObject1.method()");
-        assertEquals(1, mTestController.waitForIntValue());
-        executeJavaScript("testObject2.method()");
-        assertEquals(2, mTestController.waitForIntValue());
-    }
-
-    public void testCallMethodOnReturnedObject() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public Object getInnerObject() {
-                return new Object() {
-                    public void method(int x) { mTestController.setIntValue(x); }
-                };
-            }
-        }, "testObject");
-        executeJavaScript("testObject.getInnerObject().method(42)");
-        assertEquals(42, mTestController.waitForIntValue());
-    }
-
-    public void testReturnedObjectInjectedElsewhere() throws Throwable {
-        class InnerObject {
-            private int mNumMethodInvocations;
-            public void method() { mTestController.setIntValue(++mNumMethodInvocations); }
-        }
-        final InnerObject innerObject = new InnerObject();
-        final Object object = new Object() {
-            public InnerObject getInnerObject() {
-                return innerObject;
-            }
-        };
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getWebView().addJavascriptInterface(object, "testObject");
-                getWebView().addJavascriptInterface(innerObject, "innerObject");
-                getWebView().reload();
-            }
-        });
-        mWebViewClient.waitForOnPageFinished();
-        executeJavaScript("testObject.getInnerObject().method()");
-        assertEquals(1, mTestController.waitForIntValue());
-        executeJavaScript("innerObject.method()");
-        assertEquals(2, mTestController.waitForIntValue());
-    }
-
-    public void testMethodInvokedOnBackgroundThread() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public void captureThreadId() {
-                mTestController.setLongValue(Thread.currentThread().getId());
-            }
-        }, "testObject");
-        executeJavaScript("testObject.captureThreadId()");
-        final long threadId = mTestController.waitForLongValue();
-        assertFalse(threadId == Thread.currentThread().getId());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertFalse(threadId == Thread.currentThread().getId());
-            }
-        });
-    }
-
-    public void testPublicInheritedMethod() throws Throwable {
-        class Base {
-            public void method(int x) { mTestController.setIntValue(x); }
-        }
-        class Derived extends Base {
-        }
-        injectObjectAndReload(new Derived(), "testObject");
-        assertEquals("function", executeJavaScriptAndGetStringResult("typeof testObject.method"));
-        executeJavaScript("testObject.method(42)");
-        assertEquals(42, mTestController.waitForIntValue());
-    }
-
-    public void testPrivateInheritedMethod() throws Throwable {
-        class Base {
-            private void method() {}
-        }
-        class Derived extends Base {
-        }
-        injectObjectAndReload(new Derived(), "testObject");
-        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject.method"));
-    }
-
-    public void testOverriddenMethod() throws Throwable {
-        class Base {
-            public void method() { mTestController.setStringValue("base"); }
-        }
-        class Derived extends Base {
-            public void method() { mTestController.setStringValue("derived"); }
-        }
-        injectObjectAndReload(new Derived(), "testObject");
-        executeJavaScript("testObject.method()");
-        assertEquals("derived", mTestController.waitForStringValue());
-    }
-
-    public void testEnumerateMembers() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public void method() {}
-            private void privateMethod() {}
-            public int field;
-            private int privateField;
-        }, "testObject");
-        executeJavaScript(
-                "var result = \"\"; " +
-                "for (x in testObject) { result += \" \" + x } " +
-                "testController.setStringValue(result);");
-        // LIVECONNECT_COMPLIANCE: Should be able to enumerate members.
-        assertEquals("", mTestController.waitForStringValue());
-    }
-
-    public void testReflectPublicMethod() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public String method() { return "foo"; }
-        }, "testObject");
-        assertEquals("foo", executeJavaScriptAndGetStringResult(
-                "testObject.getClass().getMethod('method', null).invoke(testObject, null)" +
-                ".toString()"));
-    }
-
-    public void testReflectPublicField() throws Throwable {
-        injectObjectAndReload(new Object() {
-            public String field = "foo";
-        }, "testObject");
-        assertEquals("foo", executeJavaScriptAndGetStringResult(
-                "testObject.getClass().getField('field').get(testObject).toString()"));
-    }
-
-    public void testReflectPrivateMethodRaisesException() throws Throwable {
-        injectObjectAndReload(new Object() {
-            private void method() {};
-        }, "testObject");
-        assertRaisesException("testObject.getClass().getMethod('method', null)");
-        // getDeclaredMethod() is able to access a private method, but invoke()
-        // throws a Java exception.
-        assertRaisesException(
-                "testObject.getClass().getDeclaredMethod('method', null).invoke(testObject, null)");
-    }
-
-    public void testReflectPrivateFieldRaisesException() throws Throwable {
-        injectObjectAndReload(new Object() {
-            private int field;
-        }, "testObject");
-        assertRaisesException("testObject.getClass().getField('field')");
-        // getDeclaredField() is able to access a private field, but getInt()
-        // throws a Java exception.
-        assertRaisesException(
-                "testObject.getClass().getDeclaredField('field').getInt(testObject)");
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeChildFrameTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeChildFrameTest.java
deleted file mode 100644
index 3f0e2b3..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeChildFrameTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-/**
- * Part of the test suite for the WebView's Java Bridge.
- *
- * Ensures that injected objects are exposed to child frames as well as the
- * main frame.
- *
- * To run this test ...
- *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeChildFrameTest \
- *          com.android.webviewtests/android.test.InstrumentationTestRunner
- */
-
-package com.android.webviewtests;
-
-public class JavaBridgeChildFrameTest extends JavaBridgeTestBase {
-    private class TestController extends Controller {
-        private String mStringValue;
-
-       public synchronized void setStringValue(String x) {
-            mStringValue = x;
-            notifyResultIsReady();
-        }
-       public synchronized String waitForStringValue() {
-            waitForResult();
-            return mStringValue;
-        }
-    }
-
-    TestController mTestController;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestController = new TestController();
-        setUpWebView(mTestController, "testController");
-    }
-
-    public void testInjectedObjectPresentInChildFrame() throws Throwable {
-        // In the case that the test fails (i.e. the child frame doesn't get the injected object,
-        // the call to testController.setStringValue in the child frame's onload handler will
-        // not be made.
-        getActivity().getWebView().loadData(
-                "<html><head></head><body>" +
-                "<iframe id=\"childFrame\" onload=\"testController.setStringValue('PASS');\" />" +
-                "</body></html>", "text/html", null);
-        assertEquals("PASS", mTestController.waitForStringValue());
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java
deleted file mode 100644
index a0f78a4..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**
- * Part of the test suite for the WebView's Java Bridge. This class tests that
- * we correctly convert JavaScript values to Java values when passing them to
- * the methods of injected Java objects.
- *
- * The conversions should follow
- * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
- * which the implementation differs from the spec are marked with
- * LIVECONNECT_COMPLIANCE.
- * FIXME: Consider making our implementation more compliant, if it will not
- * break backwards-compatibility. See b/4408210.
- *
- * To run this test ...
- *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeCoercionTest \
- *     com.android.webviewtests/android.test.InstrumentationTestRunner
- */
-
-package com.android.webviewtests;
-
-public class JavaBridgeCoercionTest extends JavaBridgeTestBase {
-    private class TestObject extends Controller {
-        private Object objectInstance;
-        private CustomType customTypeInstance;
-        private CustomType2 customType2Instance;
-
-        private boolean mBooleanValue;
-        private byte mByteValue;
-        private char mCharValue;
-        private short mShortValue;
-        private int mIntValue;
-        private long mLongValue;
-        private float mFloatValue;
-        private double mDoubleValue;
-        private String mStringValue;
-        private Object mObjectValue;
-        private CustomType mCustomTypeValue;
-
-        public TestObject() {
-            objectInstance = new Object();
-            customTypeInstance = new CustomType();
-            customType2Instance = new CustomType2();
-        }
-
-        public Object getObjectInstance() {
-            return objectInstance;
-        }
-        public CustomType getCustomTypeInstance() {
-            return customTypeInstance;
-        }
-        public CustomType2 getCustomType2Instance() {
-            return customType2Instance;
-        }
-
-        public synchronized void setBooleanValue(boolean x) {
-            mBooleanValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setByteValue(byte x) {
-            mByteValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setCharValue(char x) {
-            mCharValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setShortValue(short x) {
-            mShortValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setIntValue(int x) {
-            mIntValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setLongValue(long x) {
-            mLongValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setFloatValue(float x) {
-            mFloatValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setDoubleValue(double x) {
-            mDoubleValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setStringValue(String x) {
-            mStringValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setObjectValue(Object x) {
-            mObjectValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized void setCustomTypeValue(CustomType x) {
-            mCustomTypeValue = x;
-            notifyResultIsReady();
-        }
-
-        public synchronized boolean waitForBooleanValue() {
-            waitForResult();
-            return mBooleanValue;
-        }
-        public synchronized byte waitForByteValue() {
-            waitForResult();
-            return mByteValue;
-        }
-        public synchronized char waitForCharValue() {
-            waitForResult();
-            return mCharValue;
-        }
-        public synchronized short waitForShortValue() {
-            waitForResult();
-            return mShortValue;
-        }
-        public synchronized int waitForIntValue() {
-            waitForResult();
-            return mIntValue;
-        }
-        public synchronized long waitForLongValue() {
-            waitForResult();
-            return mLongValue;
-        }
-        public synchronized float waitForFloatValue() {
-            waitForResult();
-            return mFloatValue;
-        }
-        public synchronized double waitForDoubleValue() {
-            waitForResult();
-            return mDoubleValue;
-        }
-        public synchronized String waitForStringValue() {
-            waitForResult();
-            return mStringValue;
-        }
-        public synchronized Object waitForObjectValue() {
-            waitForResult();
-            return mObjectValue;
-        }
-        public synchronized CustomType waitForCustomTypeValue() {
-            waitForResult();
-            return mCustomTypeValue;
-        }
-    }
-
-    // Two custom types used when testing passing objects.
-    private static class CustomType {
-    }
-    private static class CustomType2 {
-    }
-
-    private TestObject mTestObject;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestObject = new TestObject();
-        setUpWebView(mTestObject, "testObject");
-    }
-
-    // Test passing a JavaScript number in the int32 range to a method of an
-    // injected object.
-    public void testPassNumberInt32() throws Throwable {
-        executeJavaScript("testObject.setByteValue(42);");
-        assertEquals(42, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42);");
-        assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
-
-        // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
-        executeJavaScript("testObject.setCharValue(42);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        executeJavaScript("testObject.setShortValue(42);");
-        assertEquals(42, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42);");
-        assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
-
-        executeJavaScript("testObject.setIntValue(42);");
-        assertEquals(42, mTestObject.waitForIntValue());
-
-        executeJavaScript("testObject.setLongValue(42);");
-        assertEquals(42L, mTestObject.waitForLongValue());
-
-        executeJavaScript("testObject.setFloatValue(42);");
-        assertEquals(42.0f, mTestObject.waitForFloatValue());
-
-        executeJavaScript("testObject.setDoubleValue(42);");
-        assertEquals(42.0, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(42);");
-        assertNull(mTestObject.waitForObjectValue());
-
-        // The spec allows the JS engine flexibility in how to format the number.
-        executeJavaScript("testObject.setStringValue(42);");
-        String str = mTestObject.waitForStringValue();
-        assertTrue("42".equals(str) || "42.0".equals(str));
-
-        executeJavaScript("testObject.setBooleanValue(0);");
-        assertFalse(mTestObject.waitForBooleanValue());
-        // LIVECONNECT_COMPLIANCE: Should be true;
-        executeJavaScript("testObject.setBooleanValue(42);");
-        assertFalse(mTestObject.waitForBooleanValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(42);");
-        assertNull(mTestObject.waitForCustomTypeValue());
-    }
-
-    // Test passing a JavaScript number in the double range to a method of an
-    // injected object.
-    public void testPassNumberDouble() throws Throwable {
-        executeJavaScript("testObject.setByteValue(42.1);");
-        assertEquals(42, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42.1);");
-        assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Integer.MAX_VALUE + " + 42.1);");
-        assertEquals(-1, mTestObject.waitForByteValue());
-
-        // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
-        executeJavaScript("testObject.setCharValue(42.1);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        executeJavaScript("testObject.setShortValue(42.1);");
-        assertEquals(42, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42.1);");
-        assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Integer.MAX_VALUE + " + 42.1);");
-        assertEquals(-1, mTestObject.waitForShortValue());
-
-        executeJavaScript("testObject.setIntValue(42.1);");
-        assertEquals(42, mTestObject.waitForIntValue());
-        executeJavaScript("testObject.setIntValue(" + Integer.MAX_VALUE + " + 42.1);");
-        assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
-
-        executeJavaScript("testObject.setLongValue(42.1);");
-        assertEquals(42L, mTestObject.waitForLongValue());
-        // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE.
-        executeJavaScript("testObject.setLongValue(" + Long.MAX_VALUE + " + 42.1);");
-        assertEquals(Long.MIN_VALUE, mTestObject.waitForLongValue());
-
-        executeJavaScript("testObject.setFloatValue(42.1);");
-        assertEquals(42.1f, mTestObject.waitForFloatValue());
-
-        executeJavaScript("testObject.setDoubleValue(42.1);");
-        assertEquals(42.1, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(42.1);");
-        assertNull(mTestObject.waitForObjectValue());
-
-        executeJavaScript("testObject.setStringValue(42.1);");
-        assertEquals("42.1", mTestObject.waitForStringValue());
-
-        executeJavaScript("testObject.setBooleanValue(0.0);");
-        assertFalse(mTestObject.waitForBooleanValue());
-        // LIVECONNECT_COMPLIANCE: Should be true.
-        executeJavaScript("testObject.setBooleanValue(42.1);");
-        assertFalse(mTestObject.waitForBooleanValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(42.1);");
-        assertNull(mTestObject.waitForCustomTypeValue());
-    }
-
-    // Test passing JavaScript NaN to a method of an injected object.
-    public void testPassNumberNaN() throws Throwable {
-        executeJavaScript("testObject.setByteValue(Number.NaN);");
-        assertEquals(0, mTestObject.waitForByteValue());
-
-        executeJavaScript("testObject.setCharValue(Number.NaN);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        executeJavaScript("testObject.setShortValue(Number.NaN);");
-        assertEquals(0, mTestObject.waitForShortValue());
-
-        executeJavaScript("testObject.setIntValue(Number.NaN);");
-        assertEquals(0, mTestObject.waitForIntValue());
-
-        executeJavaScript("testObject.setLongValue(Number.NaN);");
-        assertEquals(0L, mTestObject.waitForLongValue());
-
-        executeJavaScript("testObject.setFloatValue(Number.NaN);");
-        assertEquals(Float.NaN, mTestObject.waitForFloatValue());
-
-        executeJavaScript("testObject.setDoubleValue(Number.NaN);");
-        assertEquals(Double.NaN, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(Number.NaN);");
-        assertNull(mTestObject.waitForObjectValue());
-
-        executeJavaScript("testObject.setStringValue(Number.NaN);");
-        assertEquals("NaN", mTestObject.waitForStringValue());
-
-        executeJavaScript("testObject.setBooleanValue(Number.NaN);");
-        assertFalse(mTestObject.waitForBooleanValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(Number.NaN);");
-        assertNull(mTestObject.waitForCustomTypeValue());
-    }
-
-    // Test passing JavaScript infinity to a method of an injected object.
-    public void testPassNumberInfinity() throws Throwable {
-        executeJavaScript("testObject.setByteValue(Infinity);");
-        assertEquals(-1, mTestObject.waitForByteValue());
-
-        // LIVECONNECT_COMPLIANCE: Should convert to maximum numeric char value.
-        executeJavaScript("testObject.setCharValue(Infinity);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        executeJavaScript("testObject.setShortValue(Infinity);");
-        assertEquals(-1, mTestObject.waitForShortValue());
-
-        executeJavaScript("testObject.setIntValue(Infinity);");
-        assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE.
-        executeJavaScript("testObject.setLongValue(Infinity);");
-        assertEquals(-1L, mTestObject.waitForLongValue());
-
-        executeJavaScript("testObject.setFloatValue(Infinity);");
-        assertEquals(Float.POSITIVE_INFINITY, mTestObject.waitForFloatValue());
-
-        executeJavaScript("testObject.setDoubleValue(Infinity);");
-        assertEquals(Double.POSITIVE_INFINITY, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(Infinity);");
-        assertNull(mTestObject.waitForObjectValue());
-
-        executeJavaScript("testObject.setStringValue(Infinity);");
-        assertEquals("Inf", mTestObject.waitForStringValue());
-
-        executeJavaScript("testObject.setBooleanValue(Infinity);");
-        assertFalse(mTestObject.waitForBooleanValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(Infinity);");
-        assertNull(mTestObject.waitForCustomTypeValue());
-    }
-
-    // Test passing a JavaScript boolean to a method of an injected object.
-    public void testPassBoolean() throws Throwable {
-        executeJavaScript("testObject.setBooleanValue(true);");
-        assertTrue(mTestObject.waitForBooleanValue());
-        executeJavaScript("testObject.setBooleanValue(false);");
-        assertFalse(mTestObject.waitForBooleanValue());
-
-        // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Boolean.
-        executeJavaScript("testObject.setObjectValue(true);");
-        assertNull(mTestObject.waitForObjectValue());
-
-        executeJavaScript("testObject.setStringValue(false);");
-        assertEquals("false", mTestObject.waitForStringValue());
-        executeJavaScript("testObject.setStringValue(true);");
-        assertEquals("true", mTestObject.waitForStringValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setByteValue(true);");
-        assertEquals(0, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(false);");
-        assertEquals(0, mTestObject.waitForByteValue());
-
-        // LIVECONNECT_COMPLIANCE: Should convert to numeric char value 1.
-        executeJavaScript("testObject.setCharValue(true);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-        executeJavaScript("testObject.setCharValue(false);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setShortValue(true);");
-        assertEquals(0, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(false);");
-        assertEquals(0, mTestObject.waitForShortValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setIntValue(true);");
-        assertEquals(0, mTestObject.waitForIntValue());
-        executeJavaScript("testObject.setIntValue(false);");
-        assertEquals(0, mTestObject.waitForIntValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setLongValue(true);");
-        assertEquals(0L, mTestObject.waitForLongValue());
-        executeJavaScript("testObject.setLongValue(false);");
-        assertEquals(0L, mTestObject.waitForLongValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setFloatValue(true);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-        executeJavaScript("testObject.setFloatValue(false);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setDoubleValue(true);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-        executeJavaScript("testObject.setDoubleValue(false);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(true);");
-        assertNull(mTestObject.waitForCustomTypeValue());
-    }
-
-    // Test passing a JavaScript string to a method of an injected object.
-    public void testPassString() throws Throwable {
-        executeJavaScript("testObject.setStringValue(\"+042.10\");");
-        assertEquals("+042.10", mTestObject.waitForStringValue());
-
-        // Make sure that we distinguish between the empty string and NULL.
-        executeJavaScript("testObject.setStringValue(\"\");");
-        assertEquals("", mTestObject.waitForStringValue());
-
-        // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.String.
-        executeJavaScript("testObject.setObjectValue(\"+042.10\");");
-        assertNull(mTestObject.waitForObjectValue());
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setByteValue(\"+042.10\");");
-        assertEquals(0, mTestObject.waitForByteValue());
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setShortValue(\"+042.10\");");
-        assertEquals(0, mTestObject.waitForShortValue());
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setIntValue(\"+042.10\");");
-        assertEquals(0, mTestObject.waitForIntValue());
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setLongValue(\"+042.10\");");
-        assertEquals(0L, mTestObject.waitForLongValue());
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setFloatValue(\"+042.10\");");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-
-        // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setDoubleValue(\"+042.10\");");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should decode and convert to numeric char value.
-        executeJavaScript("testObject.setCharValue(\"+042.10\");");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        // LIVECONNECT_COMPLIANCE: Non-empty string should convert to true.
-        executeJavaScript("testObject.setBooleanValue(\"+042.10\");");
-        assertFalse(mTestObject.waitForBooleanValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(\"+042.10\");");
-        assertNull(mTestObject.waitForCustomTypeValue());
-    }
-
-    // Test passing a JavaScript object to a method of an injected object.
-    public void testPassJavaScriptObject() throws Throwable {
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setObjectValue({foo: 42});");
-        assertNull(mTestObject.waitForObjectValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue({foo: 42});");
-        assertNull(mTestObject.waitForCustomTypeValue());
-
-        // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringValue({foo: 42});");
-        assertEquals("undefined", mTestObject.waitForStringValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteValue({foo: 42});");
-        assertEquals(0, mTestObject.waitForByteValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharValue({foo: 42});");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortValue({foo: 42});");
-        assertEquals(0, mTestObject.waitForShortValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntValue({foo: 42});");
-        assertEquals(0, mTestObject.waitForIntValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongValue({foo: 42});");
-        assertEquals(0L, mTestObject.waitForLongValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatValue({foo: 42});");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleValue({foo: 42});");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanValue({foo: 42});");
-        assertFalse(mTestObject.waitForBooleanValue());
-    }
-
-    // Test passing a Java object to a method of an injected object. Note that
-    // this test requires being able to return objects from the methods of
-    // injected objects. This is tested elsewhere.
-    public void testPassJavaObject() throws Throwable {
-        executeJavaScript("testObject.setObjectValue(testObject.getObjectInstance());");
-        assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForObjectValue());
-        executeJavaScript("testObject.setObjectValue(testObject.getCustomTypeInstance());");
-        assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForObjectValue());
-
-        executeJavaScript("testObject.setCustomTypeValue(testObject.getObjectInstance());");
-        assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForCustomTypeValue());
-        executeJavaScript("testObject.setCustomTypeValue(testObject.getCustomTypeInstance());");
-        assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForCustomTypeValue());
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception, as the types are unrelated.
-        executeJavaScript("testObject.setCustomTypeValue(testObject.getCustomType2Instance());");
-        assertTrue(mTestObject.getCustomType2Instance() ==
-                (Object)mTestObject.waitForCustomTypeValue());
-
-        // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringValue(testObject.getObjectInstance());");
-        assertEquals("undefined", mTestObject.waitForStringValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteValue(testObject.getObjectInstance());");
-        assertEquals(0, mTestObject.waitForByteValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharValue(testObject.getObjectInstance());");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortValue(testObject.getObjectInstance());");
-        assertEquals(0, mTestObject.waitForShortValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntValue(testObject.getObjectInstance());");
-        assertEquals(0, mTestObject.waitForIntValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongValue(testObject.getObjectInstance());");
-        assertEquals(0L, mTestObject.waitForLongValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatValue(testObject.getObjectInstance());");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleValue(testObject.getObjectInstance());");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-
-        // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanValue(testObject.getObjectInstance());");
-        assertFalse(mTestObject.waitForBooleanValue());
-    }
-
-    // Test passing JavaScript null to a method of an injected object.
-    public void testPassNull() throws Throwable {
-        executeJavaScript("testObject.setObjectValue(null);");
-        assertNull(mTestObject.waitForObjectValue());
-
-        executeJavaScript("testObject.setCustomTypeValue(null);");
-        assertNull(mTestObject.waitForCustomTypeValue());
-
-        executeJavaScript("testObject.setStringValue(null);");
-        assertNull(mTestObject.waitForStringValue());
-
-        executeJavaScript("testObject.setByteValue(null);");
-        assertEquals(0, mTestObject.waitForByteValue());
-
-        executeJavaScript("testObject.setCharValue(null);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        executeJavaScript("testObject.setShortValue(null);");
-        assertEquals(0, mTestObject.waitForShortValue());
-
-        executeJavaScript("testObject.setIntValue(null);");
-        assertEquals(0, mTestObject.waitForIntValue());
-
-        executeJavaScript("testObject.setLongValue(null);");
-        assertEquals(0L, mTestObject.waitForLongValue());
-
-        executeJavaScript("testObject.setFloatValue(null);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-
-        executeJavaScript("testObject.setDoubleValue(null);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-
-        executeJavaScript("testObject.setBooleanValue(null);");
-        assertFalse(mTestObject.waitForBooleanValue());
-    }
-
-    // Test passing JavaScript undefined to a method of an injected object.
-    public void testPassUndefined() throws Throwable {
-        executeJavaScript("testObject.setObjectValue(undefined);");
-        assertNull(mTestObject.waitForObjectValue());
-
-        executeJavaScript("testObject.setCustomTypeValue(undefined);");
-        assertNull(mTestObject.waitForCustomTypeValue());
-
-        // LIVECONNECT_COMPLIANCE: Should be NULL.
-        executeJavaScript("testObject.setStringValue(undefined);");
-        assertEquals("undefined", mTestObject.waitForStringValue());
-
-        executeJavaScript("testObject.setByteValue(undefined);");
-        assertEquals(0, mTestObject.waitForByteValue());
-
-        executeJavaScript("testObject.setCharValue(undefined);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-
-        executeJavaScript("testObject.setShortValue(undefined);");
-        assertEquals(0, mTestObject.waitForShortValue());
-
-        executeJavaScript("testObject.setIntValue(undefined);");
-        assertEquals(0, mTestObject.waitForIntValue());
-
-        executeJavaScript("testObject.setLongValue(undefined);");
-        assertEquals(0L, mTestObject.waitForLongValue());
-
-        executeJavaScript("testObject.setFloatValue(undefined);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-
-        executeJavaScript("testObject.setDoubleValue(undefined);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-
-        executeJavaScript("testObject.setBooleanValue(undefined);");
-        assertFalse(mTestObject.waitForBooleanValue());
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java
deleted file mode 100644
index 0ccd175..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**
- * Part of the test suite for the WebView's Java Bridge. This test tests the
- * use of fields.
- *
- * To run this test ...
- *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeFieldsTest \
- *     com.android.webviewtests/android.test.InstrumentationTestRunner
- */
-
-package com.android.webviewtests;
-
-public class JavaBridgeFieldsTest extends JavaBridgeTestBase {
-    private class TestObject extends Controller {
-        private String mStringValue;
-
-        // These methods are used to control the test.
-        public synchronized void setStringValue(String x) {
-            mStringValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized String waitForStringValue() {
-            waitForResult();
-            return mStringValue;
-        }
-
-        public boolean booleanField = true;
-        public byte byteField = 42;
-        public char charField = '\u002A';
-        public short shortField = 42;
-        public int intField = 42;
-        public long longField = 42L;
-        public float floatField = 42.0f;
-        public double doubleField = 42.0;
-        public String stringField = "foo";
-        public Object objectField = new Object();
-        public CustomType customTypeField = new CustomType();
-    }
-
-    // A custom type used when testing passing objects.
-    private class CustomType {
-    }
-
-    TestObject mTestObject;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestObject = new TestObject();
-        setUpWebView(mTestObject, "testObject");
-    }
-
-    // Note that this requires that we can pass a JavaScript string to Java.
-    protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
-        executeJavaScript("testObject.setStringValue(" + script + ");");
-        return mTestObject.waitForStringValue();
-    }
-
-    // The Java bridge does not provide access to fields.
-    // FIXME: Consider providing support for this. See See b/4408210.
-    public void testFieldTypes() throws Throwable {
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.booleanField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.byteField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.charField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.shortField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.intField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.longField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.floatField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.doubleField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.objectField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.stringField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.customTypeField"));
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java
deleted file mode 100644
index 44d5cc6..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**
- * Part of the test suite for the WebView's Java Bridge. This test checks that
- * we correctly convert Java values to JavaScript values when returning them
- * from the methods of injected Java objects.
- *
- * The conversions should follow
- * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
- * which the implementation differs from the spec are marked with
- * LIVECONNECT_COMPLIANCE.
- * FIXME: Consider making our implementation more compliant, if it will not
- * break backwards-compatibility. See b/4408210.
- *
- * To run this test ...
- *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeReturnValuesTest \
- *     com.android.webviewtests/android.test.InstrumentationTestRunner
- */
-
-package com.android.webviewtests;
-
-public class JavaBridgeReturnValuesTest extends JavaBridgeTestBase {
-    // An instance of this class is injected into the page to test returning
-    // Java values to JavaScript.
-    private class TestObject extends Controller {
-        private String mStringValue;
-        private boolean mBooleanValue;
-
-        // These four methods are used to control the test.
-        public synchronized void setStringValue(String x) {
-            mStringValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized String waitForStringValue() {
-            waitForResult();
-            return mStringValue;
-        }
-        public synchronized void setBooleanValue(boolean x) {
-            mBooleanValue = x;
-            notifyResultIsReady();
-        }
-        public synchronized boolean waitForBooleanValue() {
-            waitForResult();
-            return mBooleanValue;
-        }
-
-        public boolean getBooleanValue() {
-            return true;
-        }
-        public byte getByteValue() {
-            return 42;
-        }
-        public char getCharValue() {
-            return '\u002A';
-        }
-        public short getShortValue() {
-            return 42;
-        }
-        public int getIntValue() {
-            return 42;
-        }
-        public long getLongValue() {
-            return 42L;
-        }
-        public float getFloatValue() {
-            return 42.1f;
-        }
-        public float getFloatValueNoDecimal() {
-            return 42.0f;
-        }
-        public double getDoubleValue() {
-            return 42.1;
-        }
-        public double getDoubleValueNoDecimal() {
-            return 42.0;
-        }
-        public String getStringValue() {
-            return "foo";
-        }
-        public String getEmptyStringValue() {
-            return "";
-        }
-        public String getNullStringValue() {
-            return null;
-        }
-        public Object getObjectValue() {
-            return new Object();
-        }
-        public Object getNullObjectValue() {
-            return null;
-        }
-        public CustomType getCustomTypeValue() {
-            return new CustomType();
-        }
-        public void getVoidValue() {
-        }
-    }
-
-    // A custom type used when testing passing objects.
-    private class CustomType {
-    }
-
-    TestObject mTestObject;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestObject = new TestObject();
-        setUpWebView(mTestObject, "testObject");
-    }
-
-    // Note that this requires that we can pass a JavaScript string to Java.
-    protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
-        executeJavaScript("testObject.setStringValue(" + script + ");");
-        return mTestObject.waitForStringValue();
-    }
-
-    // Note that this requires that we can pass a JavaScript boolean to Java.
-    private boolean executeJavaScriptAndGetBooleanResult(String script) throws Throwable {
-        executeJavaScript("testObject.setBooleanValue(" + script + ");");
-        return mTestObject.waitForBooleanValue();
-    }
-
-    public void testMethodReturnTypes() throws Throwable {
-        assertEquals("boolean",
-                executeJavaScriptAndGetStringResult("typeof testObject.getBooleanValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getByteValue()"));
-        // char values are returned to JavaScript as numbers.
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getCharValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getShortValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getIntValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getLongValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getFloatValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getFloatValueNoDecimal()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValueNoDecimal()"));
-        assertEquals("string",
-                executeJavaScriptAndGetStringResult("typeof testObject.getStringValue()"));
-        assertEquals("string",
-                executeJavaScriptAndGetStringResult("typeof testObject.getEmptyStringValue()"));
-        // LIVECONNECT_COMPLIANCE: This should have type object.
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.getNullStringValue()"));
-        assertEquals("object",
-                executeJavaScriptAndGetStringResult("typeof testObject.getObjectValue()"));
-        assertEquals("object",
-                executeJavaScriptAndGetStringResult("typeof testObject.getNullObjectValue()"));
-        assertEquals("object",
-                executeJavaScriptAndGetStringResult("typeof testObject.getCustomTypeValue()"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.getVoidValue()"));
-    }
-
-    public void testMethodReturnValues() throws Throwable {
-        // We do the string comparison in JavaScript, to avoid relying on the
-        // coercion algorithm from JavaScript to Java.
-        assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getByteValue()"));
-        // char values are returned to JavaScript as numbers.
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getCharValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getShortValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getIntValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getLongValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
-                "Math.abs(42.1 - testObject.getFloatValue()) < 0.001"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
-                "42.0 === testObject.getFloatValueNoDecimal()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
-                "Math.abs(42.1 - testObject.getDoubleValue()) < 0.001"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
-                "42.0 === testObject.getDoubleValueNoDecimal()"));
-        assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.getStringValue()"));
-        assertEquals("", executeJavaScriptAndGetStringResult("testObject.getEmptyStringValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("undefined === testObject.getVoidValue()"));
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java
deleted file mode 100644
index a451015..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**
- * Common functionality for testing the WebView's Java Bridge.
- */
-
-package com.android.webviewtests;
-
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-import junit.framework.Assert;
-
-public class JavaBridgeTestBase extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
-    protected class TestWebViewClient extends WebViewClient {
-        private boolean mIsPageFinished;
-        @Override
-        public synchronized void onPageFinished(WebView webView, String url) {
-            mIsPageFinished = true;
-            notify();
-        }
-        public synchronized void waitForOnPageFinished() throws RuntimeException {
-            while (!mIsPageFinished) {
-                try {
-                    wait(5000);
-                } catch (Exception e) {
-                    continue;
-                }
-                if (!mIsPageFinished) {
-                    throw new RuntimeException("Timed out waiting for onPageFinished()");
-                }
-            }
-            mIsPageFinished = false;
-        }
-    }
-
-    protected class Controller {
-        private boolean mIsResultReady;
-
-        protected synchronized void notifyResultIsReady() {
-            mIsResultReady = true;
-            notify();
-        }
-        protected synchronized void waitForResult() {
-            while (!mIsResultReady) {
-                try {
-                    wait(5000);
-                } catch (Exception e) {
-                    continue;
-                }
-                if (!mIsResultReady) {
-                    Assert.fail("Wait timed out");
-                }
-            }
-            mIsResultReady = false;
-        }
-    }
-
-    protected TestWebViewClient mWebViewClient;
-
-    public JavaBridgeTestBase() {
-        super(WebViewStubActivity.class);
-    }
-
-    // Sets up the WebView and injects the supplied object. Intended to be called from setUp().
-    protected void setUpWebView(final Object object, final String name) throws Exception {
-        mWebViewClient = new TestWebViewClient();
-        // This starts the activity, so must be called on the test thread.
-        final WebViewStubActivity activity = getActivity();
-        // On the UI thread, load an empty page and wait for it to finish
-        // loading so that the Java object is injected.
-        try {
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    WebView webView = activity.getWebView();
-                    webView.addJavascriptInterface(object, name);
-                    webView.getSettings().setJavaScriptEnabled(true);
-                    webView.setWebViewClient(mWebViewClient);
-                    webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
-                }
-            });
-            mWebViewClient.waitForOnPageFinished();
-        } catch (Throwable e) {
-            throw new RuntimeException("Failed to set up WebView: " + Log.getStackTraceString(e));
-        }
-    }
-
-    protected void executeJavaScript(final String script) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // When a JavaScript URL is executed, if the value of the last
-                // expression evaluated is not 'undefined', this value is
-                // converted to a string and used as the new document for the
-                // frame. We don't want this behaviour, so wrap the script in
-                // an anonymous function.
-                getWebView().loadUrl("javascript:(function() { " + script + " })()");
-            }
-        });
-    }
-
-    protected WebView getWebView() {
-        return getActivity().getWebView();
-    }
-}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java b/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java
deleted file mode 100644
index ccfd3d5..0000000
--- a/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2011 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.webviewtests;
-
-import com.android.webviewtests.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.webkit.WebView;
-
-public class WebViewStubActivity extends Activity {
-    private WebView mWebView;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.webview_layout);
-        mWebView = (WebView) findViewById(R.id.web_page);
-    }
-
-    public WebView getWebView() {
-        return mWebView;
-    }
-}