Merge "Apply thumbTint and trackTint styles to Switch from xml." into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 8d70a1e..cd5c0a8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4729,7 +4729,6 @@
     method public android.graphics.drawable.Icon getLargeIcon();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
-    method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -30539,10 +30538,12 @@
     field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+    field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     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_PROVISIONED_BOOL = "carrier_volte_provisioned_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_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";
@@ -30552,6 +30553,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";
diff --git a/api/removed.txt b/api/removed.txt
index 7fc927b..6d88cb6 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,3 +1,11 @@
+package android.app {
+
+  public class Notification implements android.os.Parcelable {
+    method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+  }
+
+}
+
 package android.content.pm {
 
   public class PackageInfo implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 5a08bc3..574f0c8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4831,7 +4831,6 @@
     method public android.graphics.drawable.Icon getLargeIcon();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
-    method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -32762,10 +32761,12 @@
     field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+    field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     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_PROVISIONED_BOOL = "carrier_volte_provisioned_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_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";
@@ -32775,6 +32776,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";
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 7fc927b..6d88cb6 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,3 +1,11 @@
+package android.app {
+
+  public class Notification implements android.os.Parcelable {
+    method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+  }
+
+}
+
 package android.content.pm {
 
   public class PackageInfo implements android.os.Parcelable {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 69ba27c..13fda59 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -1688,7 +1688,7 @@
     private void runPackageImportance() throws Exception {
         String packageName = nextArgRequired();
         try {
-            int procState = mAm.getPackageProcessState(packageName);
+            int procState = mAm.getPackageProcessState(packageName, "com.android.shell");
             System.out.println(
                     ActivityManager.RunningAppProcessInfo.procStateToImportance(procState));
         } catch (RemoteException e) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b65593d..9ca206a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2345,7 +2345,8 @@
     @SystemApi
     public int getPackageImportance(String packageName) {
         try {
-            int procState = ActivityManagerNative.getDefault().getPackageProcessState(packageName);
+            int procState = ActivityManagerNative.getDefault().getPackageProcessState(packageName,
+                    mContext.getOpPackageName());
             return RunningAppProcessInfo.procStateToImportance(procState);
         } catch (RemoteException e) {
             return RunningAppProcessInfo.IMPORTANCE_GONE;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 680feae..3035e3d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2539,7 +2539,8 @@
         case GET_PACKAGE_PROCESS_STATE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String pkg = data.readString();
-            int res = getPackageProcessState(pkg);
+            String callingPackage = data.readString();
+            int res = getPackageProcessState(pkg, callingPackage);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -5868,11 +5869,13 @@
     }
 
     @Override
-    public int getPackageProcessState(String packageName) throws RemoteException {
+    public int getPackageProcessState(String packageName, String callingPackage)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(packageName);
+        data.writeString(callingPackage);
         mRemote.transact(GET_PACKAGE_PROCESS_STATE_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index e7f7e13..0328708 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -503,7 +503,8 @@
     public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException;
     public void updateDeviceOwner(String packageName) throws RemoteException;
 
-    public int getPackageProcessState(String packageName) throws RemoteException;
+    public int getPackageProcessState(String packageName, String callingPackage)
+            throws RemoteException;
 
     public boolean setProcessMemoryTrimLevel(String process, int uid, int level)
             throws RemoteException;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index aa68345..c3dece8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1749,6 +1749,7 @@
      * Stack</a> document.
      *
      * @deprecated Use {@link Builder} instead.
+     * @removed
      */
     @Deprecated
     public void setLatestEventInfo(Context context,
diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/core/java/android/security/keymaster/ExportResult.aidl
index f522355..4d9b2de 100644
--- a/core/java/android/security/keymaster/ExportResult.aidl
+++ b/core/java/android/security/keymaster/ExportResult.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java
index bb44c03..2b3ccbc 100644
--- a/core/java/android/security/keymaster/ExportResult.java
+++ b/core/java/android/security/keymaster/ExportResult.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl
index 15014b1..be739d3 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.aidl
+++ b/core/java/android/security/keymaster/KeyCharacteristics.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
index c91e20c..89300d1 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.java
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2015, The Android Open Source Project
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeymasterArgument.java b/core/java/android/security/keymaster/KeymasterArgument.java
index d1d8371..6ad53a4 100644
--- a/core/java/android/security/keymaster/KeymasterArgument.java
+++ b/core/java/android/security/keymaster/KeymasterArgument.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -39,11 +39,11 @@
                     switch (KeymasterDefs.getTagType(tag)) {
                         case KeymasterDefs.KM_ENUM:
                         case KeymasterDefs.KM_ENUM_REP:
-                        case KeymasterDefs.KM_INT:
-                        case KeymasterDefs.KM_INT_REP:
+                        case KeymasterDefs.KM_UINT:
+                        case KeymasterDefs.KM_UINT_REP:
                             return new KeymasterIntArgument(tag, in);
-                        case KeymasterDefs.KM_LONG:
-                        case KeymasterDefs.KM_LONG_REP:
+                        case KeymasterDefs.KM_ULONG:
+                        case KeymasterDefs.KM_ULONG_REP:
                             return new KeymasterLongArgument(tag, in);
                         case KeymasterDefs.KM_DATE:
                             return new KeymasterDateArgument(tag, in);
diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl
index 7aef5a6..1a73206 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.aidl
+++ b/core/java/android/security/keymaster/KeymasterArguments.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index ee0ad6d..e862252 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2015, The Android Open Source Project
+ * 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
+ *      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,
@@ -139,10 +139,10 @@
      */
     public void addUnsignedInt(int tag, long value) {
         int tagType = KeymasterDefs.getTagType(tag);
-        if ((tagType != KeymasterDefs.KM_INT) && (tagType != KeymasterDefs.KM_INT_REP)) {
+        if ((tagType != KeymasterDefs.KM_UINT) && (tagType != KeymasterDefs.KM_UINT_REP)) {
             throw new IllegalArgumentException("Not an int or repeating int tag: " + tag);
         }
-        // Keymaster's KM_INT is unsigned 32 bit.
+        // Keymaster's KM_UINT is unsigned 32 bit.
         if ((value < 0) || (value > UINT32_MAX_VALUE)) {
             throw new IllegalArgumentException("Int tag value out of range: " + value);
         }
@@ -156,14 +156,14 @@
      * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag.
      */
     public long getUnsignedInt(int tag, long defaultValue) {
-        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_INT) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_UINT) {
             throw new IllegalArgumentException("Not an int tag: " + tag);
         }
         KeymasterArgument arg = getArgumentByTag(tag);
         if (arg == null) {
             return defaultValue;
         }
-        // Keymaster's KM_INT is unsigned 32 bit.
+        // Keymaster's KM_UINT is unsigned 32 bit.
         return ((KeymasterIntArgument) arg).value & 0xffffffffL;
     }
 
@@ -175,7 +175,7 @@
      */
     public void addUnsignedLong(int tag, BigInteger value) {
         int tagType = KeymasterDefs.getTagType(tag);
-        if ((tagType != KeymasterDefs.KM_LONG) && (tagType != KeymasterDefs.KM_LONG_REP)) {
+        if ((tagType != KeymasterDefs.KM_ULONG) && (tagType != KeymasterDefs.KM_ULONG_REP)) {
             throw new IllegalArgumentException("Not a long or repeating long tag: " + tag);
         }
         addLongTag(tag, value);
@@ -187,7 +187,7 @@
      * @throws IllegalArgumentException if {@code tag} is not a repeating unsigned 64-bit long tag.
      */
     public List<BigInteger> getUnsignedLongs(int tag) {
-        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ULONG_REP) {
             throw new IllegalArgumentException("Tag is not a repeating long: " + tag);
         }
         List<BigInteger> values = new ArrayList<BigInteger>();
@@ -200,7 +200,7 @@
     }
 
     private void addLongTag(int tag, BigInteger value) {
-        // Keymaster's KM_LONG is unsigned 64 bit.
+        // Keymaster's KM_ULONG is unsigned 64 bit.
         if ((value.signum() == -1) || (value.compareTo(UINT64_MAX_VALUE) > 0)) {
             throw new IllegalArgumentException("Long tag value out of range: " + value);
         }
@@ -208,7 +208,7 @@
     }
 
     private BigInteger getLongTagValue(KeymasterArgument arg) {
-        // Keymaster's KM_LONG is unsigned 64 bit. We're forced to use BigInteger for type safety
+        // Keymaster's KM_ULONG is unsigned 64 bit. We're forced to use BigInteger for type safety
         // because there's no unsigned long type.
         return toUint64(((KeymasterLongArgument) arg).value);
     }
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
index 8f70f7c..b7cd1c9 100644
--- a/core/java/android/security/keymaster/KeymasterBlob.aidl
+++ b/core/java/android/security/keymaster/KeymasterBlob.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java
index cb95604..cd36870 100644
--- a/core/java/android/security/keymaster/KeymasterBlob.java
+++ b/core/java/android/security/keymaster/KeymasterBlob.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java
index 7d587bf..541d33e 100644
--- a/core/java/android/security/keymaster/KeymasterBlobArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
index 9c03674..67b3281 100644
--- a/core/java/android/security/keymaster/KeymasterBooleanArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java
index bffd24d..aa15e34 100644
--- a/core/java/android/security/keymaster/KeymasterDateArgument.java
+++ b/core/java/android/security/keymaster/KeymasterDateArgument.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 62c28ac..bae5455 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -33,20 +33,20 @@
     public static final int KM_INVALID = 0 << 28;
     public static final int KM_ENUM = 1 << 28;
     public static final int KM_ENUM_REP = 2 << 28;
-    public static final int KM_INT = 3 << 28;
-    public static final int KM_INT_REP = 4 << 28;
-    public static final int KM_LONG = 5 << 28;
+    public static final int KM_UINT = 3 << 28;
+    public static final int KM_UINT_REP = 4 << 28;
+    public static final int KM_ULONG = 5 << 28;
     public static final int KM_DATE = 6 << 28;
     public static final int KM_BOOL = 7 << 28;
     public static final int KM_BIGNUM = 8 << 28;
     public static final int KM_BYTES = 9 << 28;
-    public static final int KM_LONG_REP = 10 << 28;
+    public static final int KM_ULONG_REP = 10 << 28;
 
     // Tag values.
     public static final int KM_TAG_INVALID = KM_INVALID | 0;
     public static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
     public static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
-    public static final int KM_TAG_KEY_SIZE = KM_INT | 3;
+    public static final int KM_TAG_KEY_SIZE = KM_UINT | 3;
     public static final int KM_TAG_BLOCK_MODE = KM_ENUM_REP | 4;
     public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
     public static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
@@ -56,19 +56,19 @@
     public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
     public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
 
-    public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_LONG | 200;
+    public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200;
     public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
     public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
     public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
-    public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_INT | 403;
-    public static final int KM_TAG_MAX_USES_PER_BOOT = KM_INT | 404;
+    public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_UINT | 403;
+    public static final int KM_TAG_MAX_USES_PER_BOOT = KM_UINT | 404;
 
     public static final int KM_TAG_ALL_USERS = KM_BOOL | 500;
-    public static final int KM_TAG_USER_ID = KM_INT | 501;
-    public static final int KM_TAG_USER_SECURE_ID = KM_LONG_REP | 502;
+    public static final int KM_TAG_USER_ID = KM_UINT | 501;
+    public static final int KM_TAG_USER_SECURE_ID = KM_ULONG_REP | 502;
     public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
     public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
-    public static final int KM_TAG_AUTH_TIMEOUT = KM_INT | 505;
+    public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
 
     public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
     public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
@@ -82,7 +82,7 @@
     public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
     public static final int KM_TAG_NONCE = KM_BYTES | 1001;
     public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1002;
-    public static final int KM_TAG_MAC_LENGTH = KM_INT | 1003;
+    public static final int KM_TAG_MAC_LENGTH = KM_UINT | 1003;
 
     // Algorithm values.
     public static final int KM_ALGORITHM_RSA = 1;
diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java
index da81715..578d249 100644
--- a/core/java/android/security/keymaster/KeymasterIntArgument.java
+++ b/core/java/android/security/keymaster/KeymasterIntArgument.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -27,8 +27,8 @@
     public KeymasterIntArgument(int tag, int value) {
         super(tag);
         switch (KeymasterDefs.getTagType(tag)) {
-            case KeymasterDefs.KM_INT:
-            case KeymasterDefs.KM_INT_REP:
+            case KeymasterDefs.KM_UINT:
+            case KeymasterDefs.KM_UINT_REP:
             case KeymasterDefs.KM_ENUM:
             case KeymasterDefs.KM_ENUM_REP:
                 break; // OK.
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
index eb17b7e..d3d40ba 100644
--- a/core/java/android/security/keymaster/KeymasterLongArgument.java
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -27,8 +27,8 @@
     public KeymasterLongArgument(int tag, long value) {
         super(tag);
         switch (KeymasterDefs.getTagType(tag)) {
-            case KeymasterDefs.KM_LONG:
-            case KeymasterDefs.KM_LONG_REP:
+            case KeymasterDefs.KM_ULONG:
+            case KeymasterDefs.KM_ULONG_REP:
                 break; // OK.
             default:
                 throw new IllegalArgumentException("Bad long tag " + tag);
diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl
index 699e8d0..ed26c8d 100644
--- a/core/java/android/security/keymaster/OperationResult.aidl
+++ b/core/java/android/security/keymaster/OperationResult.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java
index 30659662..4c962ec 100644
--- a/core/java/android/security/keymaster/OperationResult.java
+++ b/core/java/android/security/keymaster/OperationResult.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * 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
+ *      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,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 502a6bc..92dae2e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -21041,9 +21041,6 @@
             if (sUseBrokenMakeMeasureSpec) {
                 return size + mode;
             } else {
-                if (size < 0) {
-                    throw new IllegalArgumentException("Measure spec size must be >= 0");
-                }
                 return (size & ~MODE_MASK) | (mode & MODE_MASK);
             }
         }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index a916887..48e69a1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -393,7 +393,7 @@
         }
 
         mPreserveDetachedSelection = true;
-        hideControllers();
+        hideCursorAndSpanControllers();
         stopTextActionMode();
         mPreserveDetachedSelection = false;
         mTemporaryDetach = false;
@@ -605,9 +605,9 @@
     }
 
     /**
-     * Hides the insertion controller and stops text selection mode, hiding the selection controller
+     * Hides the insertion and span controllers.
      */
-    void hideControllers() {
+    void hideCursorAndSpanControllers() {
         hideCursorControllers();
         hideSpanControllers();
     }
@@ -1104,12 +1104,12 @@
                 // ExtractEditText goes out of focus.
                 final int selStart = mTextView.getSelectionStart();
                 final int selEnd = mTextView.getSelectionEnd();
-                hideControllers();
+                hideCursorAndSpanControllers();
                 stopTextActionMode();
                 Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
             } else {
                 if (mTemporaryDetach) mPreserveDetachedSelection = true;
-                hideControllers();
+                hideCursorAndSpanControllers();
                 stopTextActionMode();
                 if (mTemporaryDetach) mPreserveDetachedSelection = false;
                 downgradeEasyCorrectionSpans();
@@ -1182,6 +1182,12 @@
                 mBlink.uncancel();
                 makeBlink();
             }
+            final InputMethodManager imm = InputMethodManager.peekInstance();
+            final boolean immFullScreen = (imm != null && imm.isFullscreenMode());
+            if (mSelectionModifierCursorController != null && mTextView.hasSelection()
+                    && !immFullScreen) {
+                mSelectionModifierCursorController.show();
+            }
         } else {
             if (mBlink != null) {
                 mBlink.cancel();
@@ -1190,7 +1196,10 @@
                 mInputContentType.enterDown = false;
             }
             // Order matters! Must be done before onParentLostFocus to rely on isShowingUp
-            hideControllers();
+            hideCursorAndSpanControllers();
+            if (mSelectionModifierCursorController != null) {
+                mSelectionModifierCursorController.hide();
+            }
             if (mSuggestionsPopupWindow != null) {
                 mSuggestionsPopupWindow.onParentLostFocus();
             }
@@ -1913,7 +1922,7 @@
 
     void onTouchUpEvent(MotionEvent event) {
         boolean selectAllGotFocus = mSelectAllOnFocus && mTextView.didTouchFocusSelect();
-        hideControllers();
+        hideCursorAndSpanControllers();
         stopTextActionMode();
         CharSequence text = mTextView.getText();
         if (!selectAllGotFocus && text.length() > 0) {
@@ -2034,7 +2043,7 @@
         if (mSuggestionsPopupWindow == null) {
             mSuggestionsPopupWindow = new SuggestionsPopupWindow();
         }
-        hideControllers();
+        hideCursorAndSpanControllers();
         stopTextActionMode();
         mSuggestionsPopupWindow.show();
     }
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/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 339038e..dac02fa 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -763,19 +763,19 @@
         }
 
         // Figure out maximum size available to this view
-        int maxAvailable = tempEnd - tempStart;
+        final int maxAvailable = tempEnd - tempStart;
 
         if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
-            // Constraints fixed both edges, so child must be an exact size
+            // Constraints fixed both edges, so child must be an exact size.
             childSpecMode = MeasureSpec.EXACTLY;
-            childSpecSize = maxAvailable;
+            childSpecSize = Math.max(0, maxAvailable);
         } else {
             if (childSize >= 0) {
-                // Child wanted an exact size. Give as much as possible
+                // Child wanted an exact size. Give as much as possible.
                 childSpecMode = MeasureSpec.EXACTLY;
 
                 if (maxAvailable >= 0) {
-                    // We have a maxmum size in this dimension.
+                    // We have a maximum size in this dimension.
                     childSpecSize = Math.min(maxAvailable, childSize);
                 } else {
                     // We can grow in this dimension.
@@ -783,20 +783,19 @@
                 }
             } else if (childSize == LayoutParams.MATCH_PARENT) {
                 // Child wanted to be as big as possible. Give all available
-                // space
+                // space.
                 childSpecMode = MeasureSpec.EXACTLY;
-                childSpecSize = maxAvailable;
+                childSpecSize = Math.max(0, maxAvailable);
             } else if (childSize == LayoutParams.WRAP_CONTENT) {
-                // Child wants to wrap content. Use AT_MOST
-                // to communicate available space if we know
-                // our max size
+                // Child wants to wrap content. Use AT_MOST to communicate
+                // available space if we know our max size.
                 if (maxAvailable >= 0) {
                     // We have a maximum size in this dimension.
                     childSpecMode = MeasureSpec.AT_MOST;
                     childSpecSize = maxAvailable;
                 } else {
                     // We can grow in this dimension. Child can be as big as it
-                    // wants
+                    // wants.
                     childSpecMode = MeasureSpec.UNSPECIFIED;
                     childSpecSize = 0;
                 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e84ba99..207605e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5230,7 +5230,8 @@
         // Phone specific code (there is no ExtractEditText on tablets).
         // ExtractEditText does not call onFocus when it is displayed, and mHasSelectionOnFocus can
         // not be set. Do the test here instead.
-        if (this instanceof ExtractEditText && hasSelection() && mEditor != null) {
+        if (isInExtractedMode() && hasSelection() && mEditor != null
+                && mEditor.mTextActionMode == null) {
             mEditor.startSelectionActionMode();
         }
 
@@ -6363,7 +6364,7 @@
         // This would stop a possible selection mode, but no such mode is started in case
         // extracted mode will start. Some text is selected though, and will trigger an action mode
         // in the extracted view.
-        mEditor.hideControllers();
+        mEditor.hideCursorAndSpanControllers();
         stopTextActionMode();
     }
 
@@ -8192,7 +8193,7 @@
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
         if (mEditor != null && visibility != VISIBLE) {
-            mEditor.hideControllers();
+            mEditor.hideCursorAndSpanControllers();
             stopTextActionMode();
         }
     }
@@ -9644,7 +9645,7 @@
         // since we are doing so explicitlty by other means and these
         // controllers interact with how selection behaves.
         if (mEditor != null) {
-            mEditor.hideControllers();
+            mEditor.hideCursorAndSpanControllers();
         }
         CharSequence text = getIterableTextForAccessibility();
         if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index fe3ab9e..e5ff51c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -74,6 +74,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -867,6 +868,16 @@
         }
     }
 
+    /**
+     * Check a simple match for the component of two ResolveInfos.
+     */
+    static boolean resolveInfoMatch(ResolveInfo lhs, ResolveInfo rhs) {
+        return lhs == null ? rhs == null
+                : lhs.activityInfo == null ? rhs.activityInfo == null
+                : Objects.equals(lhs.activityInfo.name, rhs.activityInfo.name)
+                && Objects.equals(lhs.activityInfo.packageName, rhs.activityInfo.packageName);
+    }
+
     final class DisplayResolveInfo implements TargetInfo {
         private final ResolveInfo mResolveInfo;
         private final CharSequence mDisplayLabel;
@@ -1462,7 +1473,7 @@
 
         public boolean hasResolvedTarget(ResolveInfo info) {
             for (int i = 0, N = mDisplayList.size(); i < N; i++) {
-                if (info.equals(mDisplayList.get(i).getResolveInfo())) {
+                if (resolveInfoMatch(info, mDisplayList.get(i).getResolveInfo())) {
                     return true;
                 }
             }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index faf926c..5e5450e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -16,6 +16,10 @@
     LOCAL_CFLAGS += -DPACKED=""
 endif
 
+ifneq ($(ENABLE_CPUSETS),)
+    LOCAL_CFLAGS += -DENABLE_CPUSETS
+endif
+
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
 LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 2c35a8b..bffbab7 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -588,6 +588,8 @@
     char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
     char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
     char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
+    char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
+    char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
 
     bool checkJni = false;
     property_get("dalvik.vm.checkjni", propBuf, "");
@@ -848,6 +850,24 @@
                        profileMaxStackDepth,
                        "-Xprofile-max-stack-depth:");
 
+    /*
+     * Tracing options.
+     */
+    property_get("dalvik.vm.method-trace", propBuf, "false");
+    if (strcmp(propBuf, "true") == 0) {
+        addOption("-Xmethod-trace");
+        parseRuntimeOption("dalvik.vm.method-trace-file",
+                           methodTraceFileBuf,
+                           "-Xmethod-trace-file:");
+        parseRuntimeOption("dalvik.vm.method-trace-file-siz",
+                           methodTraceFileSizeBuf,
+                           "-Xmethod-trace-file-size:");
+        property_get("dalvik.vm.method-trace-stream", propBuf, "false");
+        if (strcmp(propBuf, "true") == 0) {
+            addOption("-Xmethod-trace-stream");
+        }
+    }
+
     // Native bridge library. "0" means that native bridge is disabled.
     property_get("ro.dalvik.vm.native.bridge", propBuf, "");
     if (propBuf[0] == '\0') {
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index d14fc0f..b9fd65f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -606,7 +606,9 @@
 
         Layout layout;
         TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, start, count, textLength);
+        // Only the substring is used for measurement, so no additional context is passed in. This
+        // behavior is consistent between char[] and String specializations.
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + start, 0, count, count);
         width = layout.getAdvance();
 
         env->ReleaseStringChars(text, textArray);
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 2830724..ee8fb19 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -239,7 +239,8 @@
         if (t_pri <= ANDROID_PRIORITY_AUDIO) {
             int scheduler = sched_getscheduler(t_pid);
             if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
-                // This task wants to stay in it's current audio group so it can keep it's budget
+                // This task wants to stay in its current audio group so it can keep its budget
+                // don't update its cpuset or cgroup
                 continue;
             }
         }
@@ -247,15 +248,33 @@
         if (isDefault) {
             if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
                 // This task wants to stay at background
+                // update its cpuset so it doesn't only run on bg core(s)
+#ifdef ENABLE_CPUSETS
+                int err = set_cpuset_policy(t_pid, sp);
+                if (err != NO_ERROR) {
+                    signalExceptionForGroupError(env, -err);
+                    break;
+                }
+#endif
                 continue;
             }
         }
-
-        int err = set_sched_policy(t_pid, sp);
+        int err;
+#ifdef ENABLE_CPUSETS
+        // set both cpuset and cgroup for general threads
+        err = set_cpuset_policy(t_pid, sp);
         if (err != NO_ERROR) {
             signalExceptionForGroupError(env, -err);
             break;
         }
+#endif
+
+        err = set_sched_policy(t_pid, sp);
+        if (err != NO_ERROR) {
+            signalExceptionForGroupError(env, -err);
+            break;
+        }
+
     }
     closedir(d);
 }
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/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 246e43a33..5c974bd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -586,7 +586,7 @@
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_sensors">Sensors</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_sensors">access information about your vital signs and physical activity</string>
+    <string name="permgroupdesc_sensors">access sensor data about your vital signs</string>
 
     <!-- Title for the capability of an accessibility service to retrieve window content. -->
     <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
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/docs/html/support.jd b/docs/html/support.jd
index bbed7df..94d6478 100644
--- a/docs/html/support.jd
+++ b/docs/html/support.jd
@@ -8,80 +8,96 @@
 
 <div class="wrap" style="width:940px;">
 
-  <h1>Developer Support Resources</h1>
-<!--
-<p>A variety of support resources are available to help you report and resolve issues while you are developing apps for Android. </p>
--->
-    <div style="margin: 20px 0 0;">
+<h1>Developer Support Resources</h1>
 
-  <div class="col-8" style="margin-left:0">
-    <h3 style="font-size: 14px;line-height: 21px;color: #555;text-transform: uppercase;border-bottom: 1px solid #CCC;margin: 0 0 20px;">Code-Level Support</h3>
-    
-<h5>Community and Office Hours</h5>
-<p style="color:#888">
+<div style="margin: 20px 0 0;">
 
-<a href="https://plus.google.com/+AndroidDevelopers">Android Developers</a> on Google+<br />
-<a href="https://plus.google.com/communities/105153134372062985968">Android Development community</a> on Google+<br />
-<a href="http://groups.google.com/group/android-developers">android-developers</a> support forum<br />
-<a href="http://groups.google.com/group/android-ndk">android-ndk</a> support forum<br />
-<a href="http://groups.google.com/group/android-security-discuss">android-security-discuss</a> support forum<br />
+<div class="col-8" style="margin-left:0">
 
-  <a href="http://webchat.freenode.net/?channels=android">#android</a>, <a href="http://webchat.freenode.net/?channels=android-dev">#android-dev</a> <span style="color:#888">(IRC via irc.freenode.net)</span><br />
-</p>
+  <h3 style="font-size: 14px;line-height: 21px;color: #555;text-transform:
+    uppercase;border-bottom: 1px solid #CCC;margin: 0 0 20px;">
+    Code-Level Support</h3>
 
-<p><b>
-<a target="_blank"
-href="https://helpouts.google.com/partner/ask?vertical=programming&tags=android&origin=http:%2F%2Fdeveloper.android.com%2Fsupport.html">Ask a question in Google Helpouts</a>
-</b></p>
+  <h5>Community Resources</h5>
+  <p style="color:#888">
+
+    <a href="https://plus.google.com/+AndroidDevelopers">
+      Android Developers</a> on Google+<br />
+    <a href="https://plus.google.com/communities/105153134372062985968">
+      Android Development community</a> on Google+<br />
+    <a href="http://groups.google.com/group/android-developers">
+      android-developers</a> support forum<br />
+    <a href="http://groups.google.com/group/android-ndk">
+      android-ndk</a> support forum<br />
+    <a href="http://groups.google.com/group/android-security-discuss">
+      android-security-discuss</a> support forum<br />
+
+    <a href="http://webchat.freenode.net/?channels=android">#android</a>,
+      <a href="http://webchat.freenode.net/?channels=android-dev">#android-dev</a>
+      <span style="color:#888">(IRC via irc.freenode.net)</span><br />
+  </p>
 
 
-<h5>Send Feedback</h5>
-<p>
-  <a href="http://code.google.com/p/android/issues/entry?template=Developer%20Documentation">Report documentation bug</a><br />
-  <a href="https://code.google.com/p/android/issues/entry?template=User%20bug%20report">Report device bug</a><br />
-  <a href="https://code.google.com/p/android/issues/entry?template=Developer%20bug%20report">Report platform bug</a><br />
-</p>
-
-
-  </div>
-
-  
-  
-  <div class="col-8" style="margin-right:0">
-    <h3 style="font-size: 14px;line-height: 21px;color: #555;text-transform:
-uppercase;border-bottom: 1px solid #CCC;margin: 0 0 20px;">Google Play Support</h3>
-<h5>Help center</h5>
-<p style="color:#888">
-  <a href="http://support.google.com/googleplay/android-developer/">Help&nbsp;Center&nbsp;Home</a><br />
-  <a href="http://support.google.com/googleplay/android-developer/bin/static.py?hl=en&page=known_issues.cs">Known Issues</a><br />
-</p>
-
-<h5 id="contact">Direct support contacts for developers</h5>
-<p style="color:#888">
-  <a href=" https://support.google.com/googleplay/android-developer/troubleshooter/3049653">Registration, account issues</a><br />
-  <a href="https://support.google.com/googleplay/android-developer/troubleshooter/3055196">Publishing, app distribution issues</a><br />
-  <a href="https://support.google.com/googleplay/android-developer/troubleshooter/3055329">App visibility and discoverability</a><br />
-  <a href="https://support.google.com/googleplay/android-developer/troubleshooter/3076003">Billing and reporting</a><br />
-  <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=takedown">Inappropriate apps</a><br />
-  <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1085703&topic=15868&ctx=topic">Report a Google Play policy violation</a>
-</p>
-
-<h5>End-user support</h5>
-<p style="color:#888">
-  <a href="http://support.google.com/googleplay/bin/request.py?contact_type=contact_policy&policy=apps">Click-to-call and email support for Google Play end users</a><br />
-</p>  
-
-
-
-  <h5>Payment and Merchant Issues</h5>
-
-<p style="color:#888;margin-bottom:1.5em;">
-  <a href="http://support.google.com/checkout/sell/">Merchant&nbsp;Help&nbsp;Center&nbsp;Home<br />
-  <a href="http://support.google.com/checkout/sell/bin/static.py?hl=en&page=ts.cs&ts=2472700">Issue reporting tool<br />
-  <a href="https://productforums.google.com/forum/#!forum/checkout-merchant">checkout-merchant</a> support forum<br />
-  <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=survey">Feedback survey</a>
-</p>
+  <h5>Send Feedback</h5>
+  <p>
+    <a href="http://code.google.com/p/android/issues/entry?template=Developer%20Documentation">
+      Report documentation bug</a><br />
+    <a href="https://code.google.com/p/android/issues/entry?template=User%20bug%20report">
+      Report device bug</a><br />
+    <a href="https://code.google.com/p/android/issues/entry?template=Developer%20bug%20report">
+      Report platform bug</a><br />
+  </p>
 
 
 </div>
+
+
+
+<div class="col-8" style="margin-right:0">
+  <h3 style="font-size: 14px;line-height: 21px;color: #555;text-transform:
+    uppercase;border-bottom: 1px solid #CCC;margin: 0 0 20px;">
+      Google Play Support</h3>
+
+  <h5>Help center</h5>
+  <p>
+    <a href="http://support.google.com/googleplay/android-developer/">Help&nbsp;Center&nbsp;Home</a><br />
+  </p>
+
+  <h5 id="contact">Direct support contacts for developers</h5>
+  <p>
+    <a href=" https://support.google.com/googleplay/android-developer/troubleshooter/3049653">
+      Registration, account issues</a><br />
+    <a href="https://support.google.com/googleplay/android-developer/troubleshooter/3055196">
+      Publishing, app distribution issues</a><br />
+    <a href="https://support.google.com/googleplay/android-developer/troubleshooter/3055329">
+      App visibility and discoverability</a><br />
+    <a href="https://support.google.com/googleplay/android-developer/troubleshooter/3076003">
+      Billing and reporting</a><br />
+    <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=takedown">
+      Inappropriate apps</a><br />
+    <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1085703&topic=15868&ctx=topic">
+      Report a Google Play policy violation</a>
+  </p>
+
+  <h5>End-user support</h5>
+  <p>
+    <a href="http://support.google.com/googleplay/bin/request.py?contact_type=contact_policy&policy=apps">
+      Support for Google Play end users</a><br />
+  </p>
+
+
+
+    <h5>Payment and Merchant Issues</h5>
+
+  <p style="margin-bottom:1.5em;">
+    <a href="http://support.google.com/checkout/sell/">
+      Merchant&nbsp;Help&nbsp;Center&nbsp;Home<br />
+    <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=survey">
+      Feedback survey</a>
+  </p>
+
+
 </div>
+
+</div> <!-- end margin: 20px -->
+</div> <!-- end class:wrap -->
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 2c603e2..e235a99 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -575,7 +575,7 @@
             }
         }
 
-        private void mutate() {
+        void mutate() {
             mTransitions = mTransitions.clone();
             mStateIds = mStateIds.clone();
         }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 1ae10d3..1857345 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -170,7 +170,7 @@
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mAnimatedVectorState = new AnimatedVectorDrawableState(
-                    mAnimatedVectorState, mCallback, null);
+                    mAnimatedVectorState, mCallback, mRes);
             mMutated = true;
         }
         return this;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index b344b86..1915dd7 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -730,7 +730,7 @@
                 if (origDf != null) {
                     mDrawableFutures = origDf.clone();
                 } else {
-                    mDrawableFutures = new SparseArray<ConstantStateFuture>(mNumChildren);
+                    mDrawableFutures = new SparseArray<>(mNumChildren);
                 }
 
                 // Create futures for drawables with constant states. If a
@@ -823,6 +823,9 @@
                     final Drawable prepared = mDrawableFutures.valueAt(keyIndex).get(this);
                     mDrawables[index] = prepared;
                     mDrawableFutures.removeAt(keyIndex);
+                    if (mDrawableFutures.size() == 0) {
+                        mDrawableFutures = null;
+                    }
                     return prepared;
                 }
             }
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 8373c7f..d9469d4 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -133,6 +133,7 @@
         mLayerState.mChildren = r;
 
         ensurePadding();
+        refreshPadding();
     }
 
     LayerDrawable() {
@@ -143,6 +144,7 @@
         mLayerState = createConstantState(state, res);
         if (mLayerState.mNum > 0) {
             ensurePadding();
+            refreshPadding();
         }
     }
 
@@ -162,6 +164,7 @@
         inflateLayers(r, parser, attrs, theme);
 
         ensurePadding();
+        refreshPadding();
     }
 
     /**
@@ -431,6 +434,7 @@
         final ChildDrawable layer = createLayer(dr);
         final int index = addLayer(layer);
         ensurePadding();
+        refreshChildPadding(index, layer);
         return index;
     }
 
@@ -568,6 +572,8 @@
 
         childDrawable.mDrawable = drawable;
         mLayerState.invalidateCache();
+
+        refreshChildPadding(index, childDrawable);
     }
 
     /**
@@ -1623,6 +1629,14 @@
         mPaddingB = new int[N];
     }
 
+    void refreshPadding() {
+        final int N = mLayerState.mNum;
+        final ChildDrawable[] array = mLayerState.mChildren;
+        for (int i = 0; i < N; i++) {
+            refreshChildPadding(i, array[i]);
+        }
+    }
+
     @Override
     public ConstantState getConstantState() {
         if (mLayerState.canConstantState()) {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 6369833..bf069d3 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -198,6 +198,7 @@
 
         setColor(color);
         ensurePadding();
+        refreshPadding();
         updateLocalState();
     }
 
@@ -1013,6 +1014,7 @@
 
         if (mState.mNum > 0) {
             ensurePadding();
+            refreshPadding();
         }
 
         if (res != null) {
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index c83af11..758410a 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -59,22 +59,10 @@
  * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class StateListDrawable extends DrawableContainer {
-    private static final String TAG = StateListDrawable.class.getSimpleName();
+    private static final String TAG = "StateListDrawable";
 
     private static final boolean DEBUG = false;
 
-    /**
-     * To be proper, we should have a getter for dither (and alpha, etc.)
-     * so that proxy classes like this can save/restore their delegates'
-     * values, but we don't have getters. Since we do have setters
-     * (e.g. setDither), which this proxy forwards on, we have to have some
-     * default/initial setting.
-     *
-     * The initial setting for dither is now true, since it almost always seems
-     * to improve the quality at negligible cost.
-     */
-    private static final boolean DEFAULT_DITHER = true;
-
     private StateListState mStateListState;
     private boolean mMutated;
 
@@ -104,16 +92,16 @@
 
     @Override
     protected boolean onStateChange(int[] stateSet) {
+        final boolean changed = super.onStateChange(stateSet);
+
         int idx = mStateListState.indexOfStateSet(stateSet);
         if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states "
                 + Arrays.toString(stateSet) + " found " + idx);
         if (idx < 0) {
             idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);
         }
-        if (selectDrawable(idx)) {
-            return true;
-        }
-        return super.onStateChange(stateSet);
+
+        return selectDrawable(idx) || changed;
     }
 
     @Override
@@ -326,13 +314,14 @@
             }
         }
 
-        private void mutate() {
+        void mutate() {
             mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null;
 
             final int[][] stateSets = new int[mStateSets.length][];
             for (int i = mStateSets.length - 1; i >= 0; i--) {
                 stateSets[i] = mStateSets[i] != null ? mStateSets[i].clone() : null;
             }
+            mStateSets = stateSets;
         }
 
         int addStateSet(int[] stateSet, Drawable drawable) {
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 5e205bd..24cb055 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -15,6 +15,7 @@
 package android.graphics.drawable;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -31,10 +32,10 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.graphics.PorterDuff.Mode;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
 import android.util.Log;
 import android.util.MathUtils;
@@ -212,13 +213,24 @@
     // caching the bitmap by default is allowed.
     private boolean mAllowCaching = true;
 
+    // Given the virtual display setup, the dpi can be different than the inflation's dpi.
+    // Therefore, we need to scale the values we got from the getDimension*().
+    private int mDpiScaledWidth = 0;
+    private int mDpiScaledHeight = 0;
+    private Insets mDpiScaleInsets = Insets.NONE;
+
     public VectorDrawable() {
-        mVectorState = new VectorDrawableState();
+        this(null, null);
     }
 
-    private VectorDrawable(@NonNull VectorDrawableState state) {
-        mVectorState = state;
-        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+    private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) {
+        if (state == null) {
+            mVectorState = new VectorDrawableState();
+        } else {
+            mVectorState = state;
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        }
+        updateDimensionInfo(res, false);
     }
 
     @Override
@@ -359,18 +371,66 @@
 
     @Override
     public int getIntrinsicWidth() {
-        return (int) mVectorState.mVPathRenderer.mBaseWidth;
+        return mDpiScaledWidth;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return (int) mVectorState.mVPathRenderer.mBaseHeight;
+        return mDpiScaledHeight;
     }
 
     /** @hide */
     @Override
     public Insets getOpticalInsets() {
-        return mVectorState.mVPathRenderer.mOpticalInsets;
+        return mDpiScaleInsets;
+    }
+
+    /*
+     * Update the VectorDrawable dimension since the res can be in different Dpi now.
+     * Basically, when a new instance is created or getDimension() is called, we should update
+     * the current VectorDrawable's dimension information.
+     * Only after updateStateFromTypedArray() is called, we should called this and update the
+     * constant state's dpi info, i.e. updateConstantStateDensity == true.
+     */
+    void updateDimensionInfo(@Nullable Resources res, boolean updateConstantStateDensity) {
+        if (res != null) {
+            final int densityDpi = res.getDisplayMetrics().densityDpi;
+            final int targetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+
+            if (updateConstantStateDensity) {
+                mVectorState.mVPathRenderer.mTargetDensity = targetDensity;
+            } else {
+                final int constantStateDensity = mVectorState.mVPathRenderer.mTargetDensity;
+                if (targetDensity != constantStateDensity && constantStateDensity != 0) {
+                    mDpiScaledWidth = Bitmap.scaleFromDensity(
+                            (int) mVectorState.mVPathRenderer.mBaseWidth, constantStateDensity,
+                            targetDensity);
+                    mDpiScaledHeight = Bitmap.scaleFromDensity(
+                            (int) mVectorState.mVPathRenderer.mBaseHeight,constantStateDensity,
+                            targetDensity);
+                    final int left = Bitmap.scaleFromDensity(
+                            mVectorState.mVPathRenderer.mOpticalInsets.left, constantStateDensity,
+                            targetDensity);
+                    final int right = Bitmap.scaleFromDensity(
+                            mVectorState.mVPathRenderer.mOpticalInsets.right, constantStateDensity,
+                            targetDensity);
+                    final int top = Bitmap.scaleFromDensity(
+                            mVectorState.mVPathRenderer.mOpticalInsets.top, constantStateDensity,
+                            targetDensity);
+                    final int bottom = Bitmap.scaleFromDensity(
+                            mVectorState.mVPathRenderer.mOpticalInsets.bottom, constantStateDensity,
+                            targetDensity);
+                    mDpiScaleInsets = Insets.of(left, top, right, bottom);
+                    return;
+                }
+            }
+        }
+        // For all the other cases, like either res is null, constant state is not initialized or
+        // target density is the same as the constant state, we will just use the constant state
+        // dimensions.
+        mDpiScaledWidth = (int) mVectorState.mVPathRenderer.mBaseWidth;
+        mDpiScaledHeight = (int) mVectorState.mVPathRenderer.mBaseHeight;
+        mDpiScaleInsets = mVectorState.mVPathRenderer.mOpticalInsets;
     }
 
     @Override
@@ -393,6 +453,7 @@
             try {
                 state.mCacheDirty = true;
                 updateStateFromTypedArray(a);
+                updateDimensionInfo(t.getResources(), true /* update constant state */);
             } catch (XmlPullParserException e) {
                 throw new RuntimeException(e);
             } finally {
@@ -485,6 +546,7 @@
         inflateInternal(res, parser, attrs, theme);
 
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        updateDimensionInfo(res, true /* update constant state */);
     }
 
     private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
@@ -687,7 +749,6 @@
         int mCachedRootAlpha;
         boolean mCachedAutoMirrored;
         boolean mCacheDirty;
-
         /** Temporary paint object used to draw cached bitmaps. */
         Paint mTempPaint;
 
@@ -797,12 +858,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new VectorDrawable(this);
+            return new VectorDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new VectorDrawable(this);
+            return new VectorDrawable(this, res);
         }
 
         @Override
@@ -847,6 +908,8 @@
         int mRootAlpha = 0xFF;
         String mRootName = null;
 
+        int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+
         final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
 
         public VPathRenderer() {
@@ -886,6 +949,7 @@
             mChangingConfigurations = copy.mChangingConfigurations;
             mRootAlpha = copy.mRootAlpha;
             mRootName = copy.mRootName;
+            mTargetDensity = copy.mTargetDensity;
             if (copy.mRootName != null) {
                 mVGTargetsMap.put(copy.mRootName, this);
             }
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/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index 83dad0e..6411066 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -363,8 +363,9 @@
 
         @Override
         public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
-                byte[] additionalEntropy) throws KeyStoreException {
-            byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, additionalEntropy);
+                byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
+            byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, signature,
+                    additionalEntropy);
             if (output != null) {
                 try {
                     mBufferedOutput.write(output);
@@ -425,7 +426,7 @@
         }
 
         @Override
-        public OperationResult finish(byte[] additionalEntropy) {
+        public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
             if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
                 throw new ProviderException("AAD stream does not support additional entropy");
             }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index 83131ed..38cacd0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -353,6 +353,7 @@
             try {
                 output = mAdditionalAuthenticationDataStreamer.doFinal(
                         EmptyArray.BYTE, 0, 0,
+                        null, // no signature
                         null // no additional entropy needed flushing AAD
                         );
             } finally {
@@ -469,7 +470,10 @@
             byte[] additionalEntropy =
                     KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
                             mRng, getAdditionalEntropyAmountForFinish());
-            output = mMainDataStreamer.doFinal(input, inputOffset, inputLen, additionalEntropy);
+            output = mMainDataStreamer.doFinal(
+                    input, inputOffset, inputLen,
+                    null, // no signature involved
+                    additionalEntropy);
         } catch (KeyStoreException e) {
             switch (e.getErrorCode()) {
                 case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
@@ -727,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/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
index f80feef..10aab7e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
@@ -17,11 +17,16 @@
 package android.security.keystore;
 
 import android.annotation.NonNull;
+import android.os.IBinder;
 import android.security.KeyStore;
+import android.security.KeyStoreException;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 
+import libcore.util.EmptyArray;
+
+import java.io.ByteArrayOutputStream;
 import java.security.InvalidKeyException;
 import java.security.SignatureSpi;
 
@@ -36,6 +41,71 @@
         public NONE() {
             super(KeymasterDefs.KM_DIGEST_NONE);
         }
+
+        @Override
+        protected KeyStoreCryptoOperationStreamer createMainDataStreamer(KeyStore keyStore,
+                IBinder operationToken) {
+            return new TruncateToFieldSizeMessageStreamer(
+                    super.createMainDataStreamer(keyStore, operationToken),
+                    getGroupSizeBits());
+        }
+
+        /**
+         * Streamer which buffers all input, then truncates it to field size, and then sends it into
+         * KeyStore via the provided delegate streamer.
+         */
+        private static class TruncateToFieldSizeMessageStreamer
+                implements KeyStoreCryptoOperationStreamer {
+
+            private final KeyStoreCryptoOperationStreamer mDelegate;
+            private final int mGroupSizeBits;
+            private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream();
+            private long mConsumedInputSizeBytes;
+
+            private TruncateToFieldSizeMessageStreamer(
+                    KeyStoreCryptoOperationStreamer delegate,
+                    int groupSizeBits) {
+                mDelegate = delegate;
+                mGroupSizeBits = groupSizeBits;
+            }
+
+            @Override
+            public byte[] update(byte[] input, int inputOffset, int inputLength)
+                    throws KeyStoreException {
+                if (inputLength > 0) {
+                    mInputBuffer.write(input, inputOffset, inputLength);
+                    mConsumedInputSizeBytes += inputLength;
+                }
+                return EmptyArray.BYTE;
+            }
+
+            @Override
+            public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
+                    byte[] additionalEntropy) throws KeyStoreException {
+                if (inputLength > 0) {
+                    mConsumedInputSizeBytes += inputLength;
+                    mInputBuffer.write(input, inputOffset, inputLength);
+                }
+
+                byte[] bufferedInput = mInputBuffer.toByteArray();
+                mInputBuffer.reset();
+                // Truncate input at field size (bytes)
+                return mDelegate.doFinal(bufferedInput,
+                        0,
+                        Math.min(bufferedInput.length, ((mGroupSizeBits + 7) / 8)),
+                        signature, additionalEntropy);
+            }
+
+            @Override
+            public long getConsumedInputSizeBytes() {
+                return mConsumedInputSizeBytes;
+            }
+
+            @Override
+            public long getProducedOutputSizeBytes() {
+                return mDelegate.getProducedOutputSizeBytes();
+            }
+        }
     }
 
     public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
@@ -70,7 +140,7 @@
 
     private final int mKeymasterDigest;
 
-    private int mGroupSizeBytes = -1;
+    private int mGroupSizeBits = -1;
 
     AndroidKeyStoreECDSASignatureSpi(int keymasterDigest) {
         mKeymasterDigest = keymasterDigest;
@@ -95,14 +165,14 @@
         } else if (keySizeBits > Integer.MAX_VALUE) {
             throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
         }
-        mGroupSizeBytes = (int) ((keySizeBits + 7) / 8);
+        mGroupSizeBits = (int) keySizeBits;
 
         super.initKey(key);
     }
 
     @Override
     protected final void resetAll() {
-        mGroupSizeBytes = -1;
+        mGroupSizeBits = -1;
         super.resetAll();
     }
 
@@ -112,14 +182,21 @@
     }
 
     @Override
-    protected void addAlgorithmSpecificParametersToBegin(
+    protected final void addAlgorithmSpecificParametersToBegin(
             @NonNull KeymasterArguments keymasterArgs) {
         keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_EC);
         keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
     }
 
     @Override
-    protected int getAdditionalEntropyAmountForSign() {
-        return mGroupSizeBytes;
+    protected final int getAdditionalEntropyAmountForSign() {
+        return (mGroupSizeBits + 7) / 8;
+    }
+
+    protected final int getGroupSizeBits() {
+        if (mGroupSizeBits == -1) {
+            throw new IllegalStateException("Not initialized");
+        }
+        return mGroupSizeBits;
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
index cc858d3..d20e3af 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
@@ -234,6 +234,7 @@
         try {
             result = mChunkedStreamer.doFinal(
                     null, 0, 0,
+                    null, // no signature provided -- this invocation will generate one
                     null // no additional entropy needed -- HMAC is deterministic
                     );
         } catch (KeyStoreException e) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index 1d4ca40..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;
         }
 
@@ -150,8 +151,7 @@
 
             @Override
             public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
-                    byte[] additionalEntropy)
-                    throws KeyStoreException {
+                    byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
                 if (inputLength > 0) {
                     mConsumedInputSizeBytes += inputLength;
                     mInputBuffer.write(input, inputOffset, inputLength);
@@ -174,7 +174,8 @@
                             "Message size (" + bufferedInput.length + " bytes) must be smaller than"
                             + " modulus (" + mModulusSizeBytes + " bytes)");
                 }
-                return mDelegate.doFinal(paddedInput, 0, paddedInput.length, additionalEntropy);
+                return mDelegate.doFinal(paddedInput, 0, paddedInput.length, signature,
+                        additionalEntropy);
             }
 
             @Override
@@ -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/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
index 5cdcc41..76240dd 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -58,7 +58,7 @@
      */
     private IBinder mOperationToken;
     private long mOperationHandle;
-    private KeyStoreCryptoOperationChunkedStreamer mMessageStreamer;
+    private KeyStoreCryptoOperationStreamer mMessageStreamer;
 
     /**
      * Encountered exception which could not be immediately thrown because it was encountered inside
@@ -229,9 +229,20 @@
             throw new ProviderException("Keystore returned invalid operation handle");
         }
 
-        mMessageStreamer = new KeyStoreCryptoOperationChunkedStreamer(
+        mMessageStreamer = createMainDataStreamer(mKeyStore, opResult.token);
+    }
+
+    /**
+     * Creates a streamer which sends the message to be signed/verified into the provided KeyStore
+     *
+     * <p>This implementation returns a working streamer.
+     */
+    @NonNull
+    protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
+            KeyStore keyStore, IBinder operationToken) {
+        return new KeyStoreCryptoOperationChunkedStreamer(
                 new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
-                        mKeyStore, opResult.token));
+                        keyStore, operationToken));
     }
 
     @Override
@@ -314,7 +325,10 @@
             byte[] additionalEntropy =
                     KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
                             appRandom, getAdditionalEntropyAmountForSign());
-            signature = mMessageStreamer.doFinal(EmptyArray.BYTE, 0, 0, additionalEntropy);
+            signature = mMessageStreamer.doFinal(
+                    EmptyArray.BYTE, 0, 0,
+                    null, // no signature provided -- it'll be generated by this invocation
+                    additionalEntropy);
         } catch (InvalidKeyException | KeyStoreException e) {
             throw new SignatureException(e);
         }
@@ -329,31 +343,37 @@
             throw new SignatureException(mCachedException);
         }
 
-        boolean result;
         try {
             ensureKeystoreOperationInitialized();
-            mMessageStreamer.flush();
-            OperationResult opResult = mKeyStore.finish(mOperationToken, null, signature);
-            if (opResult == null) {
-                throw new KeyStoreConnectException();
-            }
-            switch (opResult.resultCode) {
-                case KeyStore.NO_ERROR:
-                    result = true;
-                    break;
-                case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
-                    result = false;
-                    break;
-                default:
-                    throw new SignatureException(
-                            KeyStore.getKeyStoreException(opResult.resultCode));
-            }
-        } catch (InvalidKeyException | KeyStoreException e) {
+        } catch (InvalidKeyException e) {
             throw new SignatureException(e);
         }
 
+        boolean verified;
+        try {
+            byte[] output = mMessageStreamer.doFinal(
+                    EmptyArray.BYTE, 0, 0,
+                    signature,
+                    null // no additional entropy needed -- verification is deterministic
+                    );
+            if (output.length != 0) {
+                throw new ProviderException(
+                        "Signature verification unexpected produced output: " + output.length
+                        + " bytes");
+            }
+            verified = true;
+        } catch (KeyStoreException e) {
+            switch (e.getErrorCode()) {
+                case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
+                    verified = false;
+                    break;
+                default:
+                    throw new SignatureException(e);
+            }
+        }
+
         resetWhilePreservingInitState();
-        return result;
+        return verified;
     }
 
     @Override
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
index 894d52a..ea0f4b9 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
@@ -35,8 +35,8 @@
  * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
  * operation may consume less data than provided, in which case the caller has to buffer the
  * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[]) doFinal} operations which can be used to conveniently
- * implement various JCA crypto primitives.
+ * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
+ * conveniently implement various JCA crypto primitives.
  *
  * <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
  * a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
@@ -60,7 +60,7 @@
          * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
          * be reached.
          */
-        OperationResult finish(byte[] additionalEntropy);
+        OperationResult finish(byte[] siganture, byte[] additionalEntropy);
     }
 
     // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
@@ -201,8 +201,8 @@
     }
 
     @Override
-    public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] additionalEntropy)
-            throws KeyStoreException {
+    public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
+            byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
         if (inputLength == 0) {
             // No input provided -- simplify the rest of the code
             input = EmptyArray.BYTE;
@@ -213,7 +213,7 @@
         byte[] output = update(input, inputOffset, inputLength);
         output = ArrayUtils.concat(output, flush());
 
-        OperationResult opResult = mKeyStoreStream.finish(additionalEntropy);
+        OperationResult opResult = mKeyStoreStream.finish(signature, additionalEntropy);
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
@@ -286,8 +286,8 @@
         }
 
         @Override
-        public OperationResult finish(byte[] additionalEntropy) {
-            return mKeyStore.finish(mOperationToken, null, null, additionalEntropy);
+        public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
+            return mKeyStore.finish(mOperationToken, null, signature, additionalEntropy);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
index 897bd71..062c2d4 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
@@ -28,15 +28,15 @@
  * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
  * operation may consume less data than provided, in which case the caller has to buffer the
  * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[]) doFinal} operations which can be used to conveniently
- * implement various JCA crypto primitives.
+ * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
+ * conveniently implement various JCA crypto primitives.
  *
  * @hide
  */
 interface KeyStoreCryptoOperationStreamer {
     byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
-    byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] additionalEntropy)
-            throws KeyStoreException;
+    byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
+            byte[] additionalEntropy) throws KeyStoreException;
     long getConsumedInputSizeBytes();
     long getProducedOutputSizeBytes();
 }
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/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index f529ac0..23bd238 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -329,7 +329,9 @@
                 case SimPuk:
                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
                     SecurityMode securityMode = mSecurityModel.getSecurityMode();
-                    if (securityMode != SecurityMode.None) {
+                    if (securityMode != SecurityMode.None
+                            || !mLockPatternUtils.isLockScreenDisabled(
+                            KeyguardUpdateMonitor.getCurrentUser())) {
                         showSecurityScreen(securityMode);
                     } else {
                         finish = true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 9a2f71c..bf92fda 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -93,6 +93,7 @@
         addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
         addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
         addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
+        addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler());
 
         // Pairing broadcasts
         addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index 469b776..71aefad 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -15,7 +15,6 @@
         <provider android:name="SettingsProvider" android:authorities="settings"
                   android:multiprocess="false"
                   android:exported="true"
-                  android:writePermission="android.permission.WRITE_SETTINGS"
                   android:singleUser="true"
                   android:initOrder="100" />
     </application>
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/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 80761d8..7f61fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -622,9 +622,8 @@
         synchronized (this) {
             if (DEBUG) Log.d(TAG, "onSystemReady");
             mSystemReady = true;
-            mUpdateMonitor.registerCallback(mUpdateCallback);
-
             doKeyguardLocked(null);
+            mUpdateMonitor.registerCallback(mUpdateCallback);
         }
         // Most services aren't available until the system reaches the ready state, so we
         // send it here when the device first boots.
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 3cd769e..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;
@@ -36,6 +35,7 @@
 
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.DebugTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -49,7 +49,6 @@
 import com.android.systemui.recents.views.ViewAnimation;
 
 import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 
 /**
@@ -74,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;
@@ -108,10 +107,15 @@
         public void run() {
             // Finish Recents
             if (mLaunchIntent != null) {
-                if (mLaunchOpts != null) {
-                    startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT);
-                } else {
-                    startActivityAsUser(mLaunchIntent, UserHandle.CURRENT);
+                try {
+                    if (mLaunchOpts != null) {
+                        startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT);
+                    } else {
+                        startActivityAsUser(mLaunchIntent, UserHandle.CURRENT);
+                    }
+                } catch (Exception e) {
+                    Console.logError(RecentsActivity.this,
+                            getString(R.string.recents_launch_error_message, "Home"));
                 }
             } else {
                 finish();
@@ -162,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();
             }
         }
     };
@@ -247,7 +253,7 @@
             if (mRecentsView.hasValidSearchBar()) {
                 mRecentsView.setSearchBarVisibility(View.VISIBLE);
             } else {
-                addSearchBarAppWidgetView();
+                refreshSearchWidgetView();
             }
         }
 
@@ -255,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();
@@ -387,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();
@@ -492,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);
@@ -648,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 fa97a86..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/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index a3bb129..a7afec4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -200,6 +200,7 @@
      * notifications on Keyguard, like SIM PIN/PUK.
      */
     public boolean needsFullscreenBouncer() {
+        ensureView();
         if (mKeyguardView != null) {
             SecurityMode mode = mKeyguardView.getSecurityMode();
             return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c3719d4..bacf890 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -137,6 +137,12 @@
         scheduleUpdate();
     }
 
+    public void abortKeyguardFadingOut() {
+        if (mAnimateKeyguardFadingOut) {
+            endAnimateKeyguardFadingOut();
+        }
+    }
+
     public void animateGoingToFullShade(long delay, long duration) {
         mDurationOverride = duration;
         mAnimationDelay = delay;
@@ -321,17 +327,21 @@
         mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
         mUpdatePending = false;
         updateScrims();
-        mAnimateKeyguardFadingOut = false;
         mDurationOverride = -1;
         mAnimationDelay = 0;
 
         // Make sure that we always call the listener even if we didn't start an animation.
+        endAnimateKeyguardFadingOut();
+        mAnimationStarted = false;
+        return true;
+    }
+
+    private void endAnimateKeyguardFadingOut() {
+        mAnimateKeyguardFadingOut = false;
         if (!mAnimationStarted && mOnAnimationFinished != null) {
             mOnAnimationFinished.run();
             mOnAnimationFinished = null;
         }
-        mAnimationStarted = false;
-        return true;
     }
 
     public void setBackDropView(BackDropView backDropView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index a7e8406..a69416a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -100,6 +100,7 @@
     public void show(Bundle options) {
         mShowing = true;
         mStatusBarWindowManager.setKeyguardShowing(true);
+        mScrimController.abortKeyguardFadingOut();
         reset();
     }
 
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index c5ea8bc..ebbd9e5 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -700,6 +700,15 @@
 
         final KeyStore ks = KeyStore.getInstance();
         ks.onUserRemoved(userId);
+
+        try {
+            final IGateKeeperService gk = getGateKeeperService();
+            if (gk != null) {
+                    gk.clearSecureUserId(userId);
+            }
+        } catch (RemoteException ex) {
+            Slog.w(TAG, "unable to clear GK secure user id");
+        }
     }
 
     private static final String[] VALID_SETTINGS = new String[] {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1ef1375..f031694 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3583,10 +3583,23 @@
         }
     }
 
+    private boolean hasUsageStatsPermission(String callingPackage) {
+        final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_GET_USAGE_STATS,
+                Binder.getCallingUid(), callingPackage);
+        if (mode == AppOpsManager.MODE_DEFAULT) {
+            return checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)
+                    == PackageManager.PERMISSION_GRANTED;
+        }
+        return mode == AppOpsManager.MODE_ALLOWED;
+    }
+
     @Override
-    public int getPackageProcessState(String packageName) {
-        enforceCallingPermission(android.Manifest.permission.GET_PACKAGE_IMPORTANCE,
-                "getPackageProcessState");
+    public int getPackageProcessState(String packageName, String callingPackage) {
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.GET_PACKAGE_IMPORTANCE,
+                    "getPackageProcessState");
+        }
+
         int procState = ActivityManager.PROCESS_STATE_NONEXISTENT;
         synchronized (this) {
             for (int i=mLruProcesses.size()-1; i>=0; i--) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5d56d4a..74ba404 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -113,18 +113,18 @@
 
         public void recordSuccess(String msg) {
             maybeFixupTimes();
+            result = SUCCEEDED + ": " + msg;
             if (mCountDownLatch != null) {
                 mCountDownLatch.countDown();
             }
-            result = SUCCEEDED + ": " + msg;
         }
 
         public void recordFailure(String msg) {
             maybeFixupTimes();
+            result = FAILED + ": " + msg;
             if (mCountDownLatch != null) {
                 mCountDownLatch.countDown();
             }
-            result = FAILED + ": " + msg;
         }
 
         private void maybeFixupTimes() {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4b8a10f..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.
@@ -218,20 +231,34 @@
     public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
 
     /**
+     * Flag specifying whether video telephony is available for carrier. If false: hard disabled.
+     * If true: then depends on carrier provisioning, availability, etc.
+     */
+    public static final String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
+
+    /**
      * Flag specifying whether WFC over IMS should be available for carrier: independent of
      * carrier provisioning. If false: hard disabled. If true: then depends on carrier
      * provisioning, availability etc.
      */
     public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
 
-    /** Flag specifying whether VoLTE availability is based on provisioning. */
-    public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
+    /** Flag specifying whether provisioning is required for VOLTE. */
+    public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+            = "carrier_volte_provisioning_required_bool";
 
     /** Flag specifying whether VoLTE TTY is supported. */
     public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
             = "carrier_volte_tty_supported_bool";
 
     /**
+     * Flag specifying whether IMS service can be turned off. If false then the service will not be
+     * turned-off completely, but individual features can be disabled.
+     */
+    public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL
+            = "carrier_allow_turnoff_ims_bool";
+
+    /**
      * If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
      * this is the value that should be used instead. A configuration value of
      * RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means there is no replacement value and that the default
@@ -352,9 +379,11 @@
         sDefaults.putBoolean(KEY_AUTO_RETRY_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_SETTINGS_ENABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
-        sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
+        sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
         sDefaults.putBoolean(KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL, false);
         sDefaults.putBoolean(KEY_DTMF_TYPE_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
@@ -391,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/VectorDrawableTest/res/anim/animation_favorite.xml b/tests/VectorDrawableTest/res/anim/animation_favorite.xml
index 2e2d9bb..13bd6f5 100644
--- a/tests/VectorDrawableTest/res/anim/animation_favorite.xml
+++ b/tests/VectorDrawableTest/res/anim/animation_favorite.xml
@@ -45,12 +45,6 @@
         android:valueTo="#FF00FF00" />
     <objectAnimator
         android:duration="8000"
-        android:propertyName="strokeWidth"
-        android:repeatCount="-1"
-        android:valueFrom="5"
-        android:valueTo="20" />
-    <objectAnimator
-        android:duration="8000"
         android:propertyName="fillColor"
         android:repeatCount="-1"
         android:valueFrom="#FFFF0000"
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
index 7be49a9..f93486e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
@@ -26,6 +26,7 @@
         <path
             android:name="favorite"
             android:fillColor="#ff000000"
+            android:strokeWidth="2"
             android:pathData="M2.100006104,-6
                 C0.1449127197,-6,1.600006104,-5.975006104,0,-5.975006104
                 C-1.574996948,-5.975006104,0.00309753418,-6-1.949996948-6
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;
-    }
-}
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index bbe6860..d551c8e 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -50,9 +50,11 @@
 aaptTests := \
     tests/AaptConfig_test.cpp \
     tests/AaptGroupEntry_test.cpp \
+    tests/Pseudolocales_test.cpp \
     tests/ResourceFilter_test.cpp
 
 aaptCIncludes := \
+    system/core/base/include \
     external/libpng \
     external/zlib
 
@@ -99,7 +101,6 @@
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
-
 # ==========================================================
 # Build the host executable: aapt
 # ==========================================================
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 6902a30..ca3f687 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -213,16 +213,14 @@
     Vector<StringPool::entry_style_span> spanStack;
     String16 curString;
     String16 rawString;
+    Pseudolocalizer pseudo(pseudolocalize);
     const char* errorMsg;
     int xliffDepth = 0;
     bool firstTime = true;
 
     size_t len;
     ResXMLTree::event_code_t code;
-    // Bracketing if pseudolocalization accented method specified.
-    if (pseudolocalize == PSEUDO_ACCENTED) {
-        curString.append(String16(String8("[")));
-    }
+    curString.append(pseudo.start());
     while ((code=inXml->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
         if (code == ResXMLTree::TEXT) {
             String16 text(inXml->getText(&len));
@@ -231,18 +229,12 @@
                 if (text.string()[0] == '@') {
                     // If this is a resource reference, don't do the pseudoloc.
                     pseudolocalize = NO_PSEUDOLOCALIZATION;
+                    pseudo.setMethod(pseudolocalize);
+                    curString = String16();
                 }
             }
             if (xliffDepth == 0 && pseudolocalize > 0) {
-                String16 pseudo;
-                if (pseudolocalize == PSEUDO_ACCENTED) {
-                    pseudo = pseudolocalize_string(text);
-                } else if (pseudolocalize == PSEUDO_BIDI) {
-                    pseudo = pseudobidi_string(text);
-                } else {
-                    pseudo = text;
-                }
-                curString.append(pseudo);
+                curString.append(pseudo.text(text));
             } else {
                 if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) {
                     return UNKNOWN_ERROR;
@@ -382,24 +374,7 @@
         }
     }
 
-    // Bracketing if pseudolocalization accented method specified.
-    if (pseudolocalize == PSEUDO_ACCENTED) {
-        const char16_t* str = outString->string();
-        const char16_t* p = str;
-        const char16_t* e = p + outString->size();
-        int words_cnt = 0;
-        while (p < e) {
-            if (isspace(*p)) {
-                words_cnt++;
-            }
-            p++;
-        }
-        unsigned int length = words_cnt > 3 ? outString->size() :
-            outString->size() / 2;
-        curString.append(String16(String8(" ")));
-        curString.append(pseudo_generate_expansion(length));
-        curString.append(String16(String8("]")));
-    }
+    curString.append(pseudo.end());
 
     if (code == ResXMLTree::BAD_DOCUMENT) {
             SourcePos(String8(fileName), inXml->getLineNumber()).error(
diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp
index 60aa2b2..c7fee2c 100644
--- a/tools/aapt/pseudolocalize.cpp
+++ b/tools/aapt/pseudolocalize.cpp
@@ -16,6 +16,80 @@
 static const String16 k_placeholder_open = String16("\xc2\xbb");
 static const String16 k_placeholder_close = String16("\xc2\xab");
 
+static const char16_t k_arg_start = '{';
+static const char16_t k_arg_end = '}';
+
+Pseudolocalizer::Pseudolocalizer(PseudolocalizationMethod m)
+    : mImpl(nullptr), mLastDepth(0) {
+  setMethod(m);
+}
+
+void Pseudolocalizer::setMethod(PseudolocalizationMethod m) {
+  if (mImpl) {
+    delete mImpl;
+  }
+  if (m == PSEUDO_ACCENTED) {
+    mImpl = new PseudoMethodAccent();
+  } else if (m == PSEUDO_BIDI) {
+    mImpl = new PseudoMethodBidi();
+  } else {
+    mImpl = new PseudoMethodNone();
+  }
+}
+
+String16 Pseudolocalizer::text(const String16& text) {
+  String16 out;
+  size_t depth = mLastDepth;
+  size_t lastpos, pos;
+  const size_t length= text.size();
+  const char16_t* str = text.string();
+  bool escaped = false;
+  for (lastpos = pos = 0; pos < length; pos++) {
+    char16_t c = str[pos];
+    if (escaped) {
+      escaped = false;
+      continue;
+    }
+    if (c == '\'') {
+      escaped = true;
+      continue;
+    }
+
+    if (c == k_arg_start) {
+      depth++;
+    } else if (c == k_arg_end && depth) {
+      depth--;
+    }
+
+    if (mLastDepth != depth || pos == length - 1) {
+      bool pseudo = ((mLastDepth % 2) == 0);
+      size_t nextpos = pos;
+      if (!pseudo || depth == mLastDepth) {
+        nextpos++;
+      }
+      size_t size = nextpos - lastpos;
+      if (size) {
+        String16 chunk = String16(text, size, lastpos);
+        if (pseudo) {
+          chunk = mImpl->text(chunk);
+        } else if (str[lastpos] == k_arg_start &&
+                   str[nextpos - 1] == k_arg_end) {
+          chunk = mImpl->placeholder(chunk);
+        }
+        out.append(chunk);
+      }
+      if (pseudo && depth < mLastDepth) { // End of message
+        out.append(mImpl->end());
+      } else if (!pseudo && depth > mLastDepth) { // Start of message
+        out.append(mImpl->start());
+      }
+      lastpos = nextpos;
+      mLastDepth = depth;
+    }
+  }
+  return out;
+}
+
 static const char*
 pseudolocalize_char(const char16_t c)
 {
@@ -78,8 +152,7 @@
     }
 }
 
-static bool
-is_possible_normal_placeholder_end(const char16_t c) {
+static bool is_possible_normal_placeholder_end(const char16_t c) {
     switch (c) {
         case 's': return true;
         case 'S': return true;
@@ -106,8 +179,7 @@
     }
 }
 
-String16
-pseudo_generate_expansion(const unsigned int length) {
+static String16 pseudo_generate_expansion(const unsigned int length) {
     String16 result = k_expansion_string;
     const char16_t* s = result.string();
     if (result.size() < length) {
@@ -127,18 +199,47 @@
     return result;
 }
 
+static bool is_space(const char16_t c) {
+  return (c == ' ' || c == '\t' || c == '\n');
+}
+
+String16 PseudoMethodAccent::start() {
+  String16 result;
+  if (mDepth == 0) {
+    result = String16(String8("["));
+  }
+  mWordCount = mLength = 0;
+  mDepth++;
+  return result;
+}
+
+String16 PseudoMethodAccent::end() {
+  String16 result;
+  if (mLength) {
+    result.append(String16(String8(" ")));
+    result.append(pseudo_generate_expansion(
+        mWordCount > 3 ? mLength : mLength / 2));
+  }
+  mWordCount = mLength = 0;
+  mDepth--;
+  if (mDepth == 0) {
+    result.append(String16(String8("]")));
+  }
+  return result;
+}
+
 /**
  * Converts characters so they look like they've been localized.
  *
  * Note: This leaves escape sequences untouched so they can later be
  * processed by ResTable::collectString in the normal way.
  */
-String16
-pseudolocalize_string(const String16& source)
+String16 PseudoMethodAccent::text(const String16& source)
 {
     const char16_t* s = source.string();
     String16 result;
     const size_t I = source.size();
+    bool lastspace = true;
     for (size_t i=0; i<I; i++) {
         char16_t c = s[i];
         if (c == '\\') {
@@ -170,23 +271,24 @@
             }
         } else if (c == '%') {
             // Placeholder syntax, no need to pseudolocalize
-            result += k_placeholder_open;
+            String16 chunk;
             bool end = false;
-            result.append(&c, 1);
+            chunk.append(&c, 1);
             while (!end && i < I) {
                 ++i;
                 c = s[i];
-                result.append(&c, 1);
+                chunk.append(&c, 1);
                 if (is_possible_normal_placeholder_end(c)) {
                     end = true;
                 } else if (c == 't') {
                     ++i;
                     c = s[i];
-                    result.append(&c, 1);
+                    chunk.append(&c, 1);
                     end = true;
                 }
             }
-            result += k_placeholder_close;
+            // Treat chunk as a placeholder unless it ends with %.
+            result += ((c == '%') ? chunk : placeholder(chunk));
         } else if (c == '<' || c == '&') {
             // html syntax, no need to pseudolocalize
             bool tag_closed = false;
@@ -234,35 +336,52 @@
             if (p != NULL) {
                 result += String16(p);
             } else {
+                bool space = is_space(c);
+                if (lastspace && !space) {
+                  mWordCount++;
+                }
+                lastspace = space;
                 result.append(&c, 1);
             }
+            // Count only pseudolocalizable chars and delimiters
+            mLength++;
         }
     }
     return result;
 }
+String16 PseudoMethodAccent::placeholder(const String16& source) {
+  // Surround a placeholder with brackets
+  return k_placeholder_open + source + k_placeholder_close;
+}
 
-String16
-pseudobidi_string(const String16& source)
+String16 PseudoMethodBidi::text(const String16& source)
 {
     const char16_t* s = source.string();
     String16 result;
-    result += k_rlm;
-    result += k_rlo;
+    bool lastspace = true;
+    bool space = true;
     for (size_t i=0; i<source.size(); i++) {
         char16_t c = s[i];
-        switch(c) {
-            case ' ': result += k_pdf;
-                      result += k_rlm;
-                      result.append(&c, 1);
-                      result += k_rlm;
-                      result += k_rlo;
-                      break;
-            default: result.append(&c, 1);
-                     break;
+        space = is_space(c);
+        if (lastspace && !space) {
+          // Word start
+          result += k_rlm + k_rlo;
+        } else if (!lastspace && space) {
+          // Word end
+          result += k_pdf + k_rlm;
         }
+        lastspace = space;
+        result.append(&c, 1);
     }
-    result += k_pdf;
-    result += k_rlm;
+    if (!lastspace) {
+      // End of last word
+      result += k_pdf + k_rlm;
+    }
     return result;
 }
 
+String16 PseudoMethodBidi::placeholder(const String16& source) {
+  // Surround a placeholder with directionality change sequence
+  return k_rlm + k_rlo + source + k_pdf + k_rlm;
+}
+
diff --git a/tools/aapt/pseudolocalize.h b/tools/aapt/pseudolocalize.h
index e6ab18e..71b974b 100644
--- a/tools/aapt/pseudolocalize.h
+++ b/tools/aapt/pseudolocalize.h
@@ -1,18 +1,58 @@
 #ifndef HOST_PSEUDOLOCALIZE_H
 #define HOST_PSEUDOLOCALIZE_H
 
+#include <base/macros.h>
 #include "StringPool.h"
 
-#include <string>
+class PseudoMethodImpl {
+ public:
+  virtual ~PseudoMethodImpl() {}
+  virtual String16 start() { return String16(); }
+  virtual String16 end() { return String16(); }
+  virtual String16 text(const String16& text) = 0;
+  virtual String16 placeholder(const String16& text) = 0;
+};
 
-String16 pseudolocalize_string(const String16& source);
-// Surrounds every word in the sentance with specific characters that makes
-// the word directionality RTL.
-String16 pseudobidi_string(const String16& source);
-// Generates expansion string based on the specified lenght.
-// Generated string could not be shorter that length, but it could be slightly
-// longer.
-String16 pseudo_generate_expansion(const unsigned int length);
+class PseudoMethodNone : public PseudoMethodImpl {
+ public:
+  PseudoMethodNone() {}
+  String16 text(const String16& text) { return text; }
+  String16 placeholder(const String16& text) { return text; }
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PseudoMethodNone);
+};
+
+class PseudoMethodBidi : public PseudoMethodImpl {
+ public:
+  String16 text(const String16& text);
+  String16 placeholder(const String16& text);
+};
+
+class PseudoMethodAccent : public PseudoMethodImpl {
+ public:
+  PseudoMethodAccent() : mDepth(0), mWordCount(0), mLength(0) {}
+  String16 start();
+  String16 end();
+  String16 text(const String16& text);
+  String16 placeholder(const String16& text);
+ private:
+  size_t mDepth;
+  size_t mWordCount;
+  size_t mLength;
+};
+
+class Pseudolocalizer {
+ public:
+  Pseudolocalizer(PseudolocalizationMethod m);
+  ~Pseudolocalizer() { if (mImpl) delete mImpl; }
+  void setMethod(PseudolocalizationMethod m);
+  String16 start() { return mImpl->start(); }
+  String16 end() { return mImpl->end(); }
+  String16 text(const String16& text);
+ private:
+  PseudoMethodImpl *mImpl;
+  size_t mLastDepth;
+};
 
 #endif // HOST_PSEUDOLOCALIZE_H
 
diff --git a/tools/aapt/tests/Pseudolocales_test.cpp b/tools/aapt/tests/Pseudolocales_test.cpp
new file mode 100644
index 0000000..4670e9f
--- /dev/null
+++ b/tools/aapt/tests/Pseudolocales_test.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "Bundle.h"
+#include "pseudolocalize.h"
+
+using android::String8;
+
+// In this context, 'Axis' represents a particular field in the configuration,
+// such as language or density.
+
+static void simple_helper(const char* input, const char* expected, PseudolocalizationMethod method) {
+    Pseudolocalizer pseudo(method);
+    String16 result = pseudo.start() + pseudo.text(String16(String8(input))) + pseudo.end();
+    //std::cout << String8(result).string() << std::endl;
+    ASSERT_EQ(String8(expected), String8(result));
+}
+
+static void compound_helper(const char* in1, const char* in2, const char *in3,
+                            const char* expected, PseudolocalizationMethod method) {
+    Pseudolocalizer pseudo(method);
+    String16 result = pseudo.start() + \
+                      pseudo.text(String16(String8(in1))) + \
+                      pseudo.text(String16(String8(in2))) + \
+                      pseudo.text(String16(String8(in3))) + \
+                      pseudo.end();
+    ASSERT_EQ(String8(expected), String8(result));
+}
+
+TEST(Pseudolocales, NoPseudolocalization) {
+  simple_helper("", "", NO_PSEUDOLOCALIZATION);
+  simple_helper("Hello, world", "Hello, world", NO_PSEUDOLOCALIZATION);
+
+  compound_helper("Hello,", " world", "",
+                  "Hello, world", NO_PSEUDOLOCALIZATION);
+}
+
+TEST(Pseudolocales, PlaintextAccent) {
+  simple_helper("", "[]", PSEUDO_ACCENTED);
+  simple_helper("Hello, world",
+                "[Ĥéļļö, ŵöŕļð one two]", PSEUDO_ACCENTED);
+
+  simple_helper("Hello, %1d",
+                "[Ĥéļļö, »%1d« one two]", PSEUDO_ACCENTED);
+
+  simple_helper("Battery %1d%%",
+                "[βåţţéŕý »%1d«%% one two]", PSEUDO_ACCENTED);
+
+  compound_helper("", "", "", "[]", PSEUDO_ACCENTED);
+  compound_helper("Hello,", " world", "",
+                  "[Ĥéļļö, ŵöŕļð one two]", PSEUDO_ACCENTED);
+}
+
+TEST(Pseudolocales, PlaintextBidi) {
+  simple_helper("", "", PSEUDO_BIDI);
+  simple_helper("word",
+                "\xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f",
+                PSEUDO_BIDI);
+  simple_helper("  word  ",
+                "  \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f  ",
+                PSEUDO_BIDI);
+  simple_helper("  word  ",
+                "  \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f  ",
+                PSEUDO_BIDI);
+  simple_helper("hello\n  world\n",
+                "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+                "  \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+                PSEUDO_BIDI);
+  compound_helper("hello", "\n ", " world\n",
+                "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+                "  \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+                PSEUDO_BIDI);
+}
+
+TEST(Pseudolocales, SimpleICU) {
+  // Single-fragment messages
+  simple_helper("{placeholder}", "[»{placeholder}«]", PSEUDO_ACCENTED);
+  simple_helper("{USER} is offline",
+              "[»{USER}« îš öƒƒļîñé one two]", PSEUDO_ACCENTED);
+  simple_helper("Copy from {path1} to {path2}",
+              "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]", PSEUDO_ACCENTED);
+  simple_helper("Today is {1,date} {1,time}",
+              "[Ţöðåý îš »{1,date}« »{1,time}« one two]", PSEUDO_ACCENTED);
+
+  // Multi-fragment messages
+  compound_helper("{USER}", " ", "is offline",
+                  "[»{USER}« îš öƒƒļîñé one two]",
+                  PSEUDO_ACCENTED);
+  compound_helper("Copy from ", "{path1}", " to {path2}",
+                  "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]",
+                  PSEUDO_ACCENTED);
+}
+
+TEST(Pseudolocales, ICUBidi) {
+  // Single-fragment messages
+  simple_helper("{placeholder}",
+                "\xe2\x80\x8f\xE2\x80\xae{placeholder}\xE2\x80\xac\xe2\x80\x8f",
+                PSEUDO_BIDI);
+  simple_helper(
+      "{COUNT, plural, one {one} other {other}}",
+      "{COUNT, plural, " \
+          "one {\xe2\x80\x8f\xE2\x80\xaeone\xE2\x80\xac\xe2\x80\x8f} " \
+        "other {\xe2\x80\x8f\xE2\x80\xaeother\xE2\x80\xac\xe2\x80\x8f}}",
+      PSEUDO_BIDI
+  );
+}
+
+TEST(Pseudolocales, Escaping) {
+  // Single-fragment messages
+  simple_helper("'{USER'} is offline",
+                "['{ÛŠÉŔ'} îš öƒƒļîñé one two three]", PSEUDO_ACCENTED);
+
+  // Multi-fragment messages
+  compound_helper("'{USER}", " ", "''is offline",
+                  "['{ÛŠÉŔ} ''îš öƒƒļîñé one two three]", PSEUDO_ACCENTED);
+}
+
+TEST(Pseudolocales, PluralsAndSelects) {
+  simple_helper(
+      "{COUNT, plural, one {Delete a file} other {Delete {COUNT} files}}",
+      "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+                     "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+      PSEUDO_ACCENTED
+  );
+  simple_helper(
+      "Distance is {COUNT, plural, one {# mile} other {# miles}}",
+      "[Ðîšţåñçé îš {COUNT, plural, one {# ḿîļé one two} " \
+                                 "other {# ḿîļéš one two}}]",
+      PSEUDO_ACCENTED
+  );
+  simple_helper(
+      "{1, select, female {{1} added you} " \
+        "male {{1} added you} other {{1} added you}}",
+      "[{1, select, female {»{1}« åððéð ýöû one two} " \
+        "male {»{1}« åððéð ýöû one two} other {»{1}« åððéð ýöû one two}}]",
+      PSEUDO_ACCENTED
+  );
+
+  compound_helper(
+      "{COUNT, plural, one {Delete a file} " \
+        "other {Delete ", "{COUNT}", " files}}",
+      "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+        "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+      PSEUDO_ACCENTED
+  );
+}
+
+TEST(Pseudolocales, NestedICU) {
+  simple_helper(
+      "{person, select, " \
+        "female {" \
+          "{num_circles, plural," \
+            "=0{{person} didn't add you to any of her circles.}" \
+            "=1{{person} added you to one of her circles.}" \
+            "other{{person} added you to her # circles.}}}" \
+        "male {" \
+          "{num_circles, plural," \
+            "=0{{person} didn't add you to any of his circles.}" \
+            "=1{{person} added you to one of his circles.}" \
+            "other{{person} added you to his # circles.}}}" \
+        "other {" \
+          "{num_circles, plural," \
+            "=0{{person} didn't add you to any of their circles.}" \
+            "=1{{person} added you to one of their circles.}" \
+            "other{{person} added you to their # circles.}}}}",
+      "[{person, select, " \
+        "female {" \
+          "{num_circles, plural," \
+            "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥéŕ çîŕçļéš." \
+              " one two three four five}" \
+            "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥéŕ çîŕçļéš." \
+              " one two three four}" \
+            "other{»{person}« åððéð ýöû ţö ĥéŕ # çîŕçļéš." \
+              " one two three four}}}" \
+        "male {" \
+          "{num_circles, plural," \
+            "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥîš çîŕçļéš." \
+              " one two three four five}" \
+            "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥîš çîŕçļéš." \
+              " one two three four}" \
+            "other{»{person}« åððéð ýöû ţö ĥîš # çîŕçļéš." \
+              " one two three four}}}" \
+        "other {{num_circles, plural," \
+          "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ţĥéîŕ çîŕçļéš." \
+            " one two three four five}" \
+          "=1{»{person}« åððéð ýöû ţö öñé öƒ ţĥéîŕ çîŕçļéš." \
+            " one two three four}" \
+          "other{»{person}« åððéð ýöû ţö ţĥéîŕ # çîŕçļéš." \
+            " one two three four}}}}]",
+      PSEUDO_ACCENTED
+  );
+}
+
+TEST(Pseudolocales, RedefineMethod) {
+  Pseudolocalizer pseudo(PSEUDO_ACCENTED);
+  String16 result = pseudo.text(String16(String8("Hello, ")));
+  pseudo.setMethod(NO_PSEUDOLOCALIZATION);
+  result.append(pseudo.text(String16(String8("world!"))));
+  ASSERT_EQ(String8("Ĥéļļö, world!"), String8(result));
+}