Merge "Add simple tests for Path#approximate" into oc-dev
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index 54fdb08..a8b9863 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -391,8 +391,6 @@
         s,e,_,_,_ = cam.do_3a(get_results=True, do_af=False)
         req = its.objects.manual_capture_request(s, e)
         fps = 30
-        if "60fps" in sys.argv:
-            fps = 60
         req["android.control.aeTargetFpsRange"] = [fps, fps]
         print "Capturing %dx%d with sens. %d, exp. time %.1fms" % (
                 W, H, s, e*NSEC_TO_MSEC)
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
index e0ac96f..77513c5 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
@@ -42,6 +42,10 @@
     private static final String EPHEMERAL_2_APK = "CtsEphemeralTestsEphemeralApp2.apk";
     private static final String EPHEMERAL_2_PKG = "com.android.cts.ephemeralapp2";
 
+    // a normally installed application with implicitly exposed components
+    private static final String IMPLICIT_APK = "CtsEphemeralTestsImplicitApp.apk";
+    private static final String IMPLICIT_PKG = "com.android.cts.implicitapp";
+
     // a normally installed application with no exposed components
     private static final String UNEXPOSED_APK = "CtsEphemeralTestsUnexposedApp.apk";
     private static final String UNEXPOSED_PKG = "com.android.cts.unexposedapp";
@@ -143,6 +147,7 @@
     private void installTestPackages() throws Exception {
         installApp(NORMAL_APK);
         installApp(UNEXPOSED_APK);
+        installApp(IMPLICIT_APK);
         installEphemeralApp(EPHEMERAL_1_APK);
         installEphemeralApp(EPHEMERAL_2_APK);
     }
@@ -150,6 +155,7 @@
     private void uninstallTestPackages() throws Exception {
         getDevice().uninstallPackage(NORMAL_PKG);
         getDevice().uninstallPackage(UNEXPOSED_PKG);
+        getDevice().uninstallPackage(IMPLICIT_PKG);
         getDevice().uninstallPackage(EPHEMERAL_1_PKG);
         getDevice().uninstallPackage(EPHEMERAL_2_PKG);
     }
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
index 260f37a..8f44f89 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
@@ -392,9 +392,17 @@
 //            startViewIntent.addCategory(Intent.CATEGORY_BROWSABLE);
 //            startViewIntent.setData(Uri.parse("https://cts.google.com/normal"));
 //            InstrumentationRegistry.getContext().startActivity(startViewIntent, null /*options*/);
-//            final BroadcastResult testResult = getResult();
-//            assertThat("com.android.cts.normalapp", is(testResult.packageName));
-//            assertThat("NormalWebActivity", is(testResult.activityName));
+//            final TestResult testResult = getResult();
+//            assertThat(testResult.getPackageName(),
+//                    is("com.android.cts.normalapp"));
+//            assertThat(testResult.getComponentName(),
+//                    is("NormalWebActivity"));
+//            assertThat(testResult.getStatus(),
+//                    is("PASS"));
+//            assertThat(testResult.getEphemeralPackageInfoExposed(),
+//                    is(false));
+//            assertThat(testResult.getException(),
+//                    is(nullValue()));
 //        }
 
         // We don't attempt to start the service since it will merely return and not
@@ -447,7 +455,7 @@
 
     @Test
     public void testStartExposed() throws Exception {
-        // start the exposed activity
+        // start the explicitly exposed activity
         {
             final Intent startExposedIntent = new Intent(ACTION_START_EXPOSED);
             InstrumentationRegistry
@@ -465,7 +473,7 @@
                     is(nullValue()));
         }
 
-        // start the exposed activity; directed package
+        // start the explicitly exposed activity; directed package
         {
             final Intent startExposedIntent = new Intent(ACTION_START_EXPOSED);
             startExposedIntent.setPackage("com.android.cts.normalapp");
@@ -484,7 +492,7 @@
                     is(nullValue()));
         }
 
-        // start the exposed activity; directed component
+        // start the explicitly exposed activity; directed component
         {
             final Intent startExposedIntent = new Intent(ACTION_START_EXPOSED);
             startExposedIntent.setComponent(new ComponentName(
@@ -504,6 +512,34 @@
                     is(nullValue()));
         }
 
+        // start the implicitly exposed activity; directed package
+        {
+            try {
+                final Intent startExposedIntent = new Intent(Intent.ACTION_VIEW);
+                startExposedIntent.setPackage("com.android.cts.implicitapp");
+                startExposedIntent.addCategory(Intent.CATEGORY_BROWSABLE);
+                startExposedIntent.setData(Uri.parse("https://cts.google.com/implicit"));
+                InstrumentationRegistry
+                        .getContext().startActivity(startExposedIntent, null /*options*/);
+                fail("activity started");
+            } catch (ActivityNotFoundException expected) { }
+        }
+
+        // start the implicitly exposed activity; directed component
+        {
+            try {
+                final Intent startExposedIntent = new Intent(Intent.ACTION_VIEW);
+                startExposedIntent.setComponent(new ComponentName(
+                        "com.android.cts.implicitapp",
+                        "com.android.cts.implicitapp.ImplicitActivity"));
+                startExposedIntent.addCategory(Intent.CATEGORY_BROWSABLE);
+                startExposedIntent.setData(Uri.parse("https://cts.google.com/implicit"));
+                InstrumentationRegistry
+                        .getContext().startActivity(startExposedIntent, null /*options*/);
+                fail("activity started");
+            } catch (ActivityNotFoundException expected) { }
+        }
+
         // start the exposed service; directed package
         {
             final Intent startExposedIntent = new Intent(ACTION_START_EXPOSED);
@@ -879,19 +915,28 @@
     @Test
     public void testPackageInfo() throws Exception {
         PackageInfo info;
-        // Test own package info.
+        // own package info
         info = InstrumentationRegistry.getContext().getPackageManager()
                 .getPackageInfo("com.android.cts.ephemeralapp1", 0);
         assertThat(info.packageName,
                 is("com.android.cts.ephemeralapp1"));
 
-        // Test exposed app package info.
+        // exposed application package info
         info = InstrumentationRegistry.getContext().getPackageManager()
                 .getPackageInfo("com.android.cts.normalapp", 0);
         assertThat(info.packageName,
                 is("com.android.cts.normalapp"));
 
-        // Test unexposed app package info not accessible.
+        // implicitly exposed application package info not accessible
+        try {
+            info = InstrumentationRegistry.getContext().getPackageManager()
+                    .getPackageInfo("com.android.cts.implicitapp", 0);
+            fail("Instant apps should not be able to access PackageInfo for an app that does not" +
+                    " expose itself to Instant Apps.");
+        } catch (PackageManager.NameNotFoundException expected) {
+        }
+
+        // unexposed application package info not accessible
         try {
             info = InstrumentationRegistry.getContext().getPackageManager()
                     .getPackageInfo("com.android.cts.unexposedapp", 0);
@@ -899,7 +944,8 @@
                     " expose itself to Instant Apps.");
         } catch (PackageManager.NameNotFoundException expected) {
         }
-        // Test Instant App (with visibleToInstantApp components) still isn't accessible.
+
+        // instant application (with visibleToInstantApp component) package info not accessible
         try {
             info = InstrumentationRegistry.getContext().getPackageManager()
                     .getPackageInfo("com.android.cts.ephemeralapp2", 0);
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
new file mode 100644
index 0000000..453dbcb
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    cts-aia-util \
+    android-support-test \
+    legacy-android-test
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := CtsEphemeralTestsImplicitApp
+
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/AndroidManifest.xml
new file mode 100644
index 0000000..f202a0a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?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="com.android.cts.implicitapp">
+    <uses-sdk
+        android:minSdkVersion="24" />
+
+    <application
+        android:label="@string/app_name">
+        <uses-library android:name="android.test.runner" />
+        <activity
+            android:name=".ImplicitActivity"
+            android:theme="@android:style/Theme.NoDisplay">
+            <!-- TEST: implicitly exposes this activity to instant apps -->
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="https" />
+                <data android:host="cts.google.com" />
+                <data android:path="/implicit" />
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.cts.implicitapp" />
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/res/values/strings.xml
new file mode 100644
index 0000000..90393aa
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/res/values/strings.xml
@@ -0,0 +1,18 @@
+<!-- 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.
+-->
+
+<resources>
+  <string name="app_name">ImplicitlyExposedApp</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/src/com/android/cts/implicitapp/ImplicitActivity.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/src/com/android/cts/implicitapp/ImplicitActivity.java
new file mode 100644
index 0000000..feffd84
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/src/com/android/cts/implicitapp/ImplicitActivity.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package com.android.cts.implicitapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.cts.util.TestResult;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+public class ImplicitActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        boolean canAccessInstantApp = false;
+        String exception = null;
+        try {
+            canAccessInstantApp = tryAccessingInstantApp();
+        } catch (Throwable t) {
+            exception = t.getClass().getName();
+        }
+
+        TestResult.getBuilder()
+                .setPackageName("com.android.cts.implicitapp")
+                .setComponentName("ImplicitActivity")
+                .setStatus("PASS")
+                .setException(exception)
+                .setEphemeralPackageInfoExposed(canAccessInstantApp)
+                .build()
+                .broadcast(this);
+        finish();
+    }
+
+    private boolean tryAccessingInstantApp() throws NameNotFoundException {
+        final PackageInfo info = getPackageManager()
+                .getPackageInfo("com.android.cts.ephemeralapp1", 0 /*flags*/);
+        return (info != null);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package1/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAdminService/package1/AndroidManifest.xml
index 5d63794..47f3c6a6 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package1/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package1/AndroidManifest.xml
@@ -32,7 +32,8 @@
 
         <service
                 android:name=".MyService"
-                android:exported="false">
+                android:exported="true"
+                android:permission="android.permission.BIND_DEVICE_ADMIN" >
             <intent-filter>
                 <action android:name="android.app.action.DEVICE_ADMIN_SERVICE" />
             </intent-filter>
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package2/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAdminService/package2/AndroidManifest.xml
index 5d63794..0ff8e68 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package2/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package2/AndroidManifest.xml
@@ -32,7 +32,8 @@
 
         <service
                 android:name=".MyService"
-                android:exported="false">
+                android:exported="false"
+                android:permission="android.permission.BIND_DEVICE_ADMIN" >
             <intent-filter>
                 <action android:name="android.app.action.DEVICE_ADMIN_SERVICE" />
             </intent-filter>
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package3/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAdminService/package3/AndroidManifest.xml
index 84dacbd..5d63794 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package3/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package3/AndroidManifest.xml
@@ -32,7 +32,7 @@
 
         <service
                 android:name=".MyService"
-                android:exported="true">
+                android:exported="false">
             <intent-filter>
                 <action android:name="android.app.action.DEVICE_ADMIN_SERVICE" />
             </intent-filter>
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package4/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAdminService/package4/AndroidManifest.xml
index 1b8497d..b43d086 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package4/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package4/AndroidManifest.xml
@@ -31,14 +31,14 @@
         </receiver>
         <service
                 android:name=".MyService"
-                android:exported="false">
+                android:permission="android.permission.BIND_DEVICE_ADMIN" >
             <intent-filter>
                 <action android:name="android.app.action.DEVICE_ADMIN_SERVICE" />
             </intent-filter>
         </service>
         <service
                 android:name=".MyService2"
-                android:exported="false">
+                android:permission="android.permission.BIND_DEVICE_ADMIN" >
             <intent-filter>
                 <action android:name="android.app.action.DEVICE_ADMIN_SERVICE" />
             </intent-filter>
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/AndroidManifest.xml
index 894d13c..95d203a 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/AndroidManifest.xml
@@ -31,7 +31,8 @@
         </receiver>
         <service
                 android:name="com.android.cts.deviceadminservice.MyService"
-                android:exported="false">
+                android:exported="true"
+                android:permission="android.permission.BIND_DEVICE_ADMIN" >
             <intent-filter>
                 <action android:name="android.app.action.DEVICE_ADMIN_SERVICE" />
             </intent-filter>
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
index f60abfa..79d3c3f 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
@@ -21,8 +21,8 @@
 
 import android.app.Activity;
 import android.app.ActivityOptions;
+import android.app.PictureInPictureParams;
 import android.content.BroadcastReceiver;
-import android.app.PictureInPictureArgs;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -32,6 +32,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Log;
+import android.util.Rational;
 import android.view.WindowManager;
 
 public class PipActivity extends AbstractLifecycleLogActivity {
@@ -58,12 +59,23 @@
     // Calls enterPictureInPicture() on creation
     private static final String EXTRA_ENTER_PIP = "enter_pip";
     // Used with EXTRA_AUTO_ENTER_PIP, value specifies the aspect ratio to enter PIP with
-    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO = "enter_pip_aspect_ratio";
+    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR =
+            "enter_pip_aspect_ratio_numerator";
+    // Used with EXTRA_AUTO_ENTER_PIP, value specifies the aspect ratio to enter PIP with
+    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR =
+            "enter_pip_aspect_ratio_denominator";
     // Calls setPictureInPictureAspectRatio with the aspect ratio specified in the value
-    private static final String EXTRA_SET_ASPECT_RATIO = "set_aspect_ratio";
+    private static final String EXTRA_SET_ASPECT_RATIO_NUMERATOR = "set_aspect_ratio_numerator";
+    // Calls setPictureInPictureAspectRatio with the aspect ratio specified in the value
+    private static final String EXTRA_SET_ASPECT_RATIO_DENOMINATOR = "set_aspect_ratio_denominator";
     // Calls setPictureInPictureAspectRatio with the aspect ratio specified in the value with a
     // fixed delay
-    private static final String EXTRA_SET_ASPECT_RATIO_WITH_DELAY = "set_aspect_ratio_with_delay";
+    private static final String EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR =
+            "set_aspect_ratio_with_delay_numerator";
+    // Calls setPictureInPictureAspectRatio with the aspect ratio specified in the value with a
+    // fixed delay
+    private static final String EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR =
+            "set_aspect_ratio_with_delay_denominator";
     // Adds a click listener to finish this activity when it is clicked
     private static final String EXTRA_TAP_TO_FINISH = "tap_to_finish";
     // Calls requestAutoEnterPictureInPicture() with the value provided
@@ -102,14 +114,17 @@
                         startIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                         startActivity(startIntent);
 
-                        if (intent.hasExtra(EXTRA_SET_ASPECT_RATIO_WITH_DELAY)) {
+                        if (intent.hasExtra(EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR)
+                                && intent.hasExtra(EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR)) {
                             // Ugly, but required to wait for the startActivity to actually start
                             // the activity...
                             mHandler.postDelayed(() -> {
-                                PictureInPictureArgs args = new PictureInPictureArgs();
-                                args.setAspectRatio(Float.valueOf(intent.getStringExtra(
-                                        EXTRA_SET_ASPECT_RATIO_WITH_DELAY)));
-                                setPictureInPictureArgs(args);
+                                final PictureInPictureParams.Builder builder =
+                                        new PictureInPictureParams.Builder();
+                                builder.setAspectRatio(getAspectRatio(intent,
+                                        EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR,
+                                        EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR));
+                                setPictureInPictureParams(builder.build());
                             }, 100);
                         }
                         break;
@@ -142,26 +157,33 @@
 
         // Enter picture in picture with the given aspect ratio if provided
         if (getIntent().hasExtra(EXTRA_ENTER_PIP)) {
-            if (getIntent().hasExtra(EXTRA_ENTER_PIP_ASPECT_RATIO)) {
+            if (getIntent().hasExtra(EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR)
+                    && getIntent().hasExtra(EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR)) {
                 try {
-                    final float aspectRatio = Float.valueOf(getIntent().getStringExtra(
-                            EXTRA_ENTER_PIP_ASPECT_RATIO));
-                    enterPictureInPictureMode(new PictureInPictureArgs(aspectRatio, null));
+                    final PictureInPictureParams.Builder builder =
+                            new PictureInPictureParams.Builder();
+                    builder.setAspectRatio(getAspectRatio(getIntent(),
+                            EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR,
+                            EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR));
+                    enterPictureInPictureMode(builder.build());
                 } catch (Exception e) {
                     // This call can fail intentionally if the aspect ratio is too extreme
                 }
             } else {
-                enterPictureInPictureMode();
+                enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
             }
         }
 
         // We need to wait for either enterPictureInPicture() or requestAutoEnterPictureInPicture()
         // to be called before setting the aspect ratio
-        if (getIntent().hasExtra(EXTRA_SET_ASPECT_RATIO)) {
-            final float aspectRatio = Float.valueOf(getIntent().getStringExtra(
-                    EXTRA_SET_ASPECT_RATIO));
+        if (getIntent().hasExtra(EXTRA_SET_ASPECT_RATIO_NUMERATOR)
+                && getIntent().hasExtra(EXTRA_SET_ASPECT_RATIO_DENOMINATOR)) {
+            final PictureInPictureParams.Builder builder =
+                    new PictureInPictureParams.Builder();
+            builder.setAspectRatio(getAspectRatio(getIntent(),
+                    EXTRA_SET_ASPECT_RATIO_NUMERATOR, EXTRA_SET_ASPECT_RATIO_DENOMINATOR));
             try {
-                setPictureInPictureArgs(new PictureInPictureArgs(aspectRatio, null));
+                setPictureInPictureParams(builder.build());
             } catch (Exception e) {
                 // This call can fail intentionally if the aspect ratio is too extreme
             }
@@ -214,7 +236,7 @@
 
         // Enter PIP on move to background
         if (getIntent().hasExtra(EXTRA_ENTER_PIP_ON_PAUSE)) {
-            enterPictureInPictureMode();
+            enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
         }
     }
 
@@ -223,7 +245,7 @@
         super.onStop();
 
         if (getIntent().hasExtra(EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP) && !mEnteredPictureInPicture) {
-            Log.w("PipActivity", "Unexpected onStop() called before entering picture-in-picture");
+            Log.w(TAG, "Unexpected onStop() called before entering picture-in-picture");
             finish();
         }
     }
@@ -239,6 +261,13 @@
     public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         super.onPictureInPictureModeChanged(isInPictureInPictureMode);
 
+        // Fail early if the activity state does not match the dispatched state
+        if (isInPictureInPictureMode() != isInPictureInPictureMode) {
+            Log.w(TAG, "Received onPictureInPictureModeChanged mode=" + isInPictureInPictureMode
+                    + " activityState=" + isInPictureInPictureMode());
+            finish();
+        }
+
         // Mark that we've entered picture-in-picture so that we can stop checking for
         // EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP
         if (isInPictureInPictureMode) {
@@ -250,7 +279,7 @@
             // checking that the stacks ever changed). Therefor, we need to delay here slightly to
             // allow the tests to verify that the stacks have changed before re-entering.
             mHandler.postDelayed(() -> {
-                enterPictureInPictureMode();
+                enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
             }, 1000);
         }
     }
@@ -284,4 +313,13 @@
     protected String getTag() {
         return TAG;
     }
+
+    /**
+     * @return a {@link Rational} aspect ratio from the given intent and extras.
+     */
+    private Rational getAspectRatio(Intent intent, String extraNum, String extraDenom) {
+        return new Rational(
+                Integer.valueOf(intent.getStringExtra(extraNum)),
+                Integer.valueOf(intent.getStringExtra(extraDenom)));
+    }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index 038eb8d..65f507e 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -49,9 +49,16 @@
 
     private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
     private static final String EXTRA_ENTER_PIP = "enter_pip";
-    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO = "enter_pip_aspect_ratio";
-    private static final String EXTRA_SET_ASPECT_RATIO = "set_aspect_ratio";
-    private static final String EXTRA_SET_ASPECT_RATIO_WITH_DELAY = "set_aspect_ratio_with_delay";
+    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR =
+            "enter_pip_aspect_ratio_numerator";
+    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR =
+            "enter_pip_aspect_ratio_denominator";
+    private static final String EXTRA_SET_ASPECT_RATIO_NUMERATOR = "set_aspect_ratio_numerator";
+    private static final String EXTRA_SET_ASPECT_RATIO_DENOMINATOR = "set_aspect_ratio_denominator";
+    private static final String EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR =
+            "set_aspect_ratio_with_delay_numerator";
+    private static final String EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR =
+            "set_aspect_ratio_with_delay_denominator";
     private static final String EXTRA_ENTER_PIP_ON_PAUSE = "enter_pip_on_pause";
     private static final String EXTRA_TAP_TO_FINISH = "tap_to_finish";
     private static final String EXTRA_START_ACTIVITY = "start_activity";
@@ -91,11 +98,13 @@
     private static final float FLOAT_COMPARE_EPSILON = 0.005f;
 
     // Corresponds to com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio
-    private static final float MIN_ASPECT_RATIO = 1f / 2.39f;
-    private static final float BELOW_MIN_ASPECT_RATIO = MIN_ASPECT_RATIO - FLOAT_COMPARE_EPSILON;
+    private static final int MIN_ASPECT_RATIO_NUMERATOR = 100;
+    private static final int MIN_ASPECT_RATIO_DENOMINATOR = 239;
+    private static final int BELOW_MIN_ASPECT_RATIO_DENOMINATOR = MIN_ASPECT_RATIO_DENOMINATOR + 1;
     // Corresponds to com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio
-    private static final float MAX_ASPECT_RATIO = 2.39f;
-    private static final float ABOVE_MAX_ASPECT_RATIO = MAX_ASPECT_RATIO + FLOAT_COMPARE_EPSILON;
+    private static final int MAX_ASPECT_RATIO_NUMERATOR = 239;
+    private static final int MAX_ASPECT_RATIO_DENOMINATOR = 100;
+    private static final int ABOVE_MAX_ASPECT_RATIO_NUMERATOR = MAX_ASPECT_RATIO_NUMERATOR + 1;
 
     public void testEnterPictureInPictureMode() throws Exception {
         pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"), PIP_ACTIVITY,
@@ -270,42 +279,44 @@
     }
 
     public void testEnterPipAspectRatioMin() throws Exception {
-        testEnterPipAspectRatio(MAX_ASPECT_RATIO);
+        testEnterPipAspectRatio(MIN_ASPECT_RATIO_NUMERATOR, MIN_ASPECT_RATIO_DENOMINATOR);
     }
 
     public void testEnterPipAspectRatioMax() throws Exception {
-        testEnterPipAspectRatio(MIN_ASPECT_RATIO);
+        testEnterPipAspectRatio(MAX_ASPECT_RATIO_NUMERATOR, MAX_ASPECT_RATIO_DENOMINATOR);
     }
 
-    private void testEnterPipAspectRatio(float aspectRatio) throws Exception {
+    private void testEnterPipAspectRatio(int num, int denom) throws Exception {
         if (!supportsPip()) return;
 
         launchActivity(PIP_ACTIVITY,
                 EXTRA_ENTER_PIP, "true",
-                EXTRA_ENTER_PIP_ASPECT_RATIO, Float.toString(aspectRatio));
+                EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR, Integer.toString(num),
+                EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR, Integer.toString(denom));
         assertPinnedStackExists();
 
         // Assert that we have entered PIP and that the aspect ratio is correct
         Rectangle pinnedStackBounds =
                 mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getBounds();
         assertTrue(floatEquals((float) pinnedStackBounds.width / pinnedStackBounds.height,
-                aspectRatio));
+                (float) num / denom));
     }
 
     public void testResizePipAspectRatioMin() throws Exception {
-        testResizePipAspectRatio(MIN_ASPECT_RATIO);
+        testResizePipAspectRatio(MIN_ASPECT_RATIO_NUMERATOR, MIN_ASPECT_RATIO_DENOMINATOR);
     }
 
     public void testResizePipAspectRatioMax() throws Exception {
-        testResizePipAspectRatio(MAX_ASPECT_RATIO);
+        testResizePipAspectRatio(MAX_ASPECT_RATIO_NUMERATOR, MAX_ASPECT_RATIO_DENOMINATOR);
     }
 
-    private void testResizePipAspectRatio(float aspectRatio) throws Exception {
+    private void testResizePipAspectRatio(int num, int denom) throws Exception {
         if (!supportsPip()) return;
 
         launchActivity(PIP_ACTIVITY,
                 EXTRA_ENTER_PIP, "true",
-                EXTRA_SET_ASPECT_RATIO, Float.toString(aspectRatio));
+                EXTRA_SET_ASPECT_RATIO_NUMERATOR, Integer.toString(num),
+                EXTRA_SET_ASPECT_RATIO_DENOMINATOR, Integer.toString(denom));
         assertPinnedStackExists();
 
         // Hacky, but we need to wait for the enterPictureInPicture animation to complete and
@@ -314,7 +325,8 @@
         mAmWmState.waitForWithAmState(mDevice, (state) -> {
             Rectangle pinnedStackBounds = state.getStackById(PINNED_STACK_ID).getBounds();
             boolean isValidAspectRatio = floatEquals(
-                    (float) pinnedStackBounds.width / pinnedStackBounds.height, aspectRatio);
+                    (float) pinnedStackBounds.width / pinnedStackBounds.height,
+                    (float) num / denom);
             result[0] = isValidAspectRatio;
             return isValidAspectRatio;
         }, "Waiting for pinned stack to be resized");
@@ -322,45 +334,54 @@
     }
 
     public void testEnterPipExtremeAspectRatioMin() throws Exception {
-        testEnterPipExtremeAspectRatio(BELOW_MIN_ASPECT_RATIO);
+        testEnterPipExtremeAspectRatio(MIN_ASPECT_RATIO_NUMERATOR,
+                BELOW_MIN_ASPECT_RATIO_DENOMINATOR);
     }
 
     public void testEnterPipExtremeAspectRatioMax() throws Exception {
-        testEnterPipExtremeAspectRatio(ABOVE_MAX_ASPECT_RATIO);
+        testEnterPipExtremeAspectRatio(ABOVE_MAX_ASPECT_RATIO_NUMERATOR,
+                MAX_ASPECT_RATIO_DENOMINATOR);
     }
 
-    private void testEnterPipExtremeAspectRatio(float aspectRatio) throws Exception {
+    private void testEnterPipExtremeAspectRatio(int num, int denom) throws Exception {
         if (!supportsPip()) return;
 
         // Assert that we could not create a pinned stack with an extreme aspect ratio
         launchActivity(PIP_ACTIVITY,
                 EXTRA_ENTER_PIP, "true",
-                EXTRA_ENTER_PIP_ASPECT_RATIO, Float.toString(aspectRatio));
+                EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR, Integer.toString(num),
+                EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR, Integer.toString(denom));
         assertPinnedStackDoesNotExist();
     }
 
     public void testSetPipExtremeAspectRatioMin() throws Exception {
-        testSetPipExtremeAspectRatio(BELOW_MIN_ASPECT_RATIO);
+        testSetPipExtremeAspectRatio(MIN_ASPECT_RATIO_NUMERATOR,
+                BELOW_MIN_ASPECT_RATIO_DENOMINATOR);
     }
 
     public void testSetPipExtremeAspectRatioMax() throws Exception {
-        testSetPipExtremeAspectRatio(ABOVE_MAX_ASPECT_RATIO);
+        testSetPipExtremeAspectRatio(ABOVE_MAX_ASPECT_RATIO_NUMERATOR,
+                MAX_ASPECT_RATIO_DENOMINATOR);
     }
 
-    private void testSetPipExtremeAspectRatio(float aspectRatio) throws Exception {
+    private void testSetPipExtremeAspectRatio(int num, int denom) throws Exception {
         if (!supportsPip()) return;
 
         // Try to resize the a normal pinned stack to an extreme aspect ratio and ensure that
         // fails (the aspect ratio remains the same)
         launchActivity(PIP_ACTIVITY,
                 EXTRA_ENTER_PIP, "true",
-                EXTRA_ENTER_PIP_ASPECT_RATIO, Float.toString(MAX_ASPECT_RATIO),
-                EXTRA_SET_ASPECT_RATIO, Float.toString(aspectRatio));
+                EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR,
+                        Integer.toString(MAX_ASPECT_RATIO_NUMERATOR),
+                EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR,
+                        Integer.toString(MAX_ASPECT_RATIO_DENOMINATOR),
+                EXTRA_SET_ASPECT_RATIO_NUMERATOR, Integer.toString(num),
+                EXTRA_SET_ASPECT_RATIO_DENOMINATOR, Integer.toString(denom));
         assertPinnedStackExists();
         Rectangle pinnedStackBounds =
                 mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getBounds();
         assertTrue(floatEquals((float) pinnedStackBounds.width / pinnedStackBounds.height,
-                MAX_ASPECT_RATIO));
+                (float) MAX_ASPECT_RATIO_NUMERATOR / MAX_ASPECT_RATIO_DENOMINATOR));
     }
 
     public void testDisallowPipLaunchFromStoppedActivity() throws Exception {
@@ -434,7 +455,8 @@
         // Launch the PIP activity on pause, and set the aspect ratio
         launchActivity(PIP_ACTIVITY,
                 EXTRA_ENTER_PIP_ON_PAUSE, "true",
-                EXTRA_SET_ASPECT_RATIO, Float.toString(MAX_ASPECT_RATIO));
+                EXTRA_SET_ASPECT_RATIO_NUMERATOR, Integer.toString(MAX_ASPECT_RATIO_NUMERATOR),
+                EXTRA_SET_ASPECT_RATIO_DENOMINATOR, Integer.toString(MAX_ASPECT_RATIO_DENOMINATOR));
 
         // Go home while the pip activity is open to trigger auto-PIP
         launchHomeActivity();
@@ -446,7 +468,8 @@
         mAmWmState.waitForWithAmState(mDevice, (state) -> {
             Rectangle pinnedStackBounds = state.getStackById(PINNED_STACK_ID).getBounds();
             boolean isValidAspectRatio = floatEquals(
-                    (float) pinnedStackBounds.width / pinnedStackBounds.height, MAX_ASPECT_RATIO);
+                    (float) pinnedStackBounds.width / pinnedStackBounds.height,
+                    (float) MAX_ASPECT_RATIO_NUMERATOR / MAX_ASPECT_RATIO_DENOMINATOR);
             result[0] = isValidAspectRatio;
             return isValidAspectRatio;
         }, "Waiting for pinned stack to be resized");
@@ -806,8 +829,9 @@
 
         // Trigger it to go back to fullscreen and try to set the aspect ratio, and ensure that the
         // call to set the aspect ratio did not prevent the PiP from returning to fullscreen
-        executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_EXPAND_PIP + " -e "
-                + EXTRA_SET_ASPECT_RATIO_WITH_DELAY + " 1.23456789");
+        executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_EXPAND_PIP
+                + " -e " + EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR + " 123456789"
+                + " -e " + EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR + " 100000000");
         mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, FULLSCREEN_WORKSPACE_STACK_ID);
         assertPinnedStackDoesNotExist();
     }
@@ -851,6 +875,9 @@
         assertPinnedStackExists();
         int taskId = mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getTopTask().mTaskId;
 
+        // Ensure that we don't any any other overlays as a result of launching into PIP
+        launchHomeActivity();
+
         // Launch task overlay activity into PiP activity task
         launchActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId, PINNED_STACK_ID);
 
@@ -858,10 +885,7 @@
         executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_FINISH);
         mAmWmState.waitForWithAmState(mDevice, (amState) -> {
             ActivityStack stack = amState.getStackById(PINNED_STACK_ID);
-            if (stack != null) {
-                return false;
-            }
-            return true;
+            return stack == null;
         }, "Waiting for pinned stack to be removed...");
         assertPinnedStackDoesNotExist();
     }
@@ -908,15 +932,13 @@
         if (expectTopTaskHasActivity) {
             ActivityTask topTask = mAmWmState.getAmState().getStackById(
                     FULLSCREEN_WORKSPACE_STACK_ID).getTopTask();
-            Activity topActivity = topTask.mActivities.get(0);
-            assertTrue(topActivity.name.equals(ActivityManagerTestBase.getActivityComponentName(
+            assertTrue(topTask.containsActivity(ActivityManagerTestBase.getActivityComponentName(
                     activityName)));
         }
         if (expectBottomTaskHasActivity) {
             ActivityTask bottomTask = mAmWmState.getAmState().getStackById(
                     FULLSCREEN_WORKSPACE_STACK_ID).getBottomTask();
-            Activity bottomActivity = bottomTask.mActivities.get(0);
-            assertTrue(bottomActivity.name.equals(ActivityManagerTestBase.getActivityComponentName(
+            assertTrue(bottomTask.containsActivity(ActivityManagerTestBase.getActivityComponentName(
                     activityName)));
         }
     }
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
index 6565215..56fed31 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
@@ -607,6 +607,18 @@
         public String getResizeMode() {
             return mResizeMode;
         }
+
+        /**
+         * @return whether this task contains the given activity.
+         */
+        public boolean containsActivity(String activityName) {
+            for (Activity activity : mActivities) {
+                if (activity.name.equals(activityName)) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     static class Activity {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java
index 786ff40..430c612 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java
@@ -62,9 +62,9 @@
 
         final Parcelable result;
         if (sResponse != null) {
-            result = sResponse.asFillResponse(structure);
+            result = sResponse.asFillResponse((id) -> Helper.findNodeByResourceId(structure, id));
         } else if (sDataset != null) {
-            result = sDataset.asDataset(structure);
+            result = sDataset.asDataset((id) -> Helper.findNodeByResourceId(structure, id));
         } else {
             throw new IllegalStateException("no dataset or response");
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index b456dd7..9f5368f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -22,11 +22,11 @@
 import static android.autofillservice.cts.Helper.getAutofillIds;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
-import android.autofillservice.cts.CannedFillResponse.Builder;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillCallback;
+import android.service.autofill.FillContext;
 import android.service.autofill.FillResponse;
 import android.service.autofill.SaveInfo;
 import android.view.autofill.AutofillId;
@@ -38,6 +38,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 /**
  * Helper class used to produce a {@link FillResponse} based on expected fields that should be
@@ -66,7 +67,7 @@
     private final IntentSender mAuthentication;
     private final String[] mAuthenticationIds;
     private final String[] mIgnoredIds;
-    private final CharSequence mNegativeActionLabel;
+    private final int mNegativeActionStyle;
     private final IntentSender mNegativeActionListener;
     private final int mFlags;
 
@@ -81,7 +82,7 @@
         mAuthentication = builder.mAuthentication;
         mAuthenticationIds = builder.mAuthenticationIds;
         mIgnoredIds = builder.mIgnoredIds;
-        mNegativeActionLabel = builder.mNegativeActionLabel;
+        mNegativeActionStyle = builder.mNegativeActionStyle;
         mNegativeActionListener = builder.mNegativeActionListener;
         mFlags = builder.mFlags;
     }
@@ -96,45 +97,37 @@
      * Creates a new response, replacing the dataset field ids by the real ids from the assist
      * structure.
      */
-    FillResponse asFillResponse(AssistStructure structure) {
+    FillResponse asFillResponse(Function<String, ViewNode> nodeResolver) {
         final FillResponse.Builder builder = new FillResponse.Builder();
         if (mDatasets != null) {
             for (CannedDataset cannedDataset : mDatasets) {
-                final Dataset dataset = cannedDataset.asDataset(structure);
+                final Dataset dataset = cannedDataset.asDataset(nodeResolver);
                 assertWithMessage("Cannot create datase").that(dataset).isNotNull();
                 builder.addDataset(dataset);
             }
         }
         if (mRequiredSavableIds != null) {
-            final SaveInfo.Builder saveInfo;
-
-            if (mRequiredSavableIds == null) {
-                saveInfo = new SaveInfo.Builder(mSaveType, null);
-            } else {
-                saveInfo = new SaveInfo.Builder(mSaveType,
-                        getAutofillIds(structure, mRequiredSavableIds));
-            }
+            final SaveInfo.Builder saveInfo = new SaveInfo.Builder(mSaveType,
+                    getAutofillIds(nodeResolver, mRequiredSavableIds));
 
             saveInfo.setFlags(mFlags);
 
             if (mOptionalSavableIds != null) {
-                saveInfo.setOptionalIds(getAutofillIds(structure, mOptionalSavableIds));
+                saveInfo.setOptionalIds(getAutofillIds(nodeResolver, mOptionalSavableIds));
             }
             if (mSaveDescription != null) {
                 saveInfo.setDescription(mSaveDescription);
             }
-            if (mNegativeActionLabel != null) {
-                saveInfo.setNegativeAction(mNegativeActionLabel, mNegativeActionListener);
-            }
+            saveInfo.setNegativeAction(mNegativeActionStyle, mNegativeActionListener);
             builder.setSaveInfo(saveInfo.build());
         }
         if (mIgnoredIds != null) {
-            builder.setIgnoredIds(getAutofillIds(structure, mIgnoredIds));
+            builder.setIgnoredIds(getAutofillIds(nodeResolver, mIgnoredIds));
         }
         return builder
                 .setClientState(mExtras)
-                .setAuthentication(getAutofillIds(structure, mAuthenticationIds), mAuthentication,
-                        mPresentation)
+                .setAuthentication(getAutofillIds(nodeResolver, mAuthenticationIds),
+                        mAuthentication, mPresentation)
                 .build();
     }
 
@@ -163,7 +156,7 @@
         private IntentSender mAuthentication;
         private String[] mAuthenticationIds;
         private String[] mIgnoredIds;
-        private CharSequence mNegativeActionLabel;
+        private int mNegativeActionStyle;
         private IntentSender mNegativeActionListener;
         private int mFlags;
 
@@ -246,9 +239,9 @@
         /**
          * Sets the negative action spec.
          */
-        public Builder setNegativeAction(CharSequence label,
+        public Builder setNegativeAction(int style,
                 IntentSender listener) {
-            mNegativeActionLabel = label;
+            mNegativeActionStyle = style;
             mNegativeActionListener = listener;
             return this;
         }
@@ -291,7 +284,7 @@
         /**
          * Creates a new dataset, replacing the field ids by the real ids from the assist structure.
          */
-        Dataset asDataset(AssistStructure structure) {
+        Dataset asDataset(Function<String, ViewNode> nodeResolver) {
             final Dataset.Builder builder = (mPresentation == null)
                     ? new Dataset.Builder()
                     : new Dataset.Builder(mPresentation);
@@ -299,9 +292,8 @@
             if (mFieldValues != null) {
                 for (Map.Entry<String, AutofillValue> entry : mFieldValues.entrySet()) {
                     final String resourceId = entry.getKey();
-                    final ViewNode node = findNodeByResourceId(structure, resourceId);
+                    final ViewNode node = nodeResolver.apply(resourceId);
                     if (node == null) {
-                        dumpStructure("asDataset()", structure);
                         throw new AssertionError("No node with resource id " + resourceId);
                     }
                     final AutofillId id = node.getAutofillId();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index e19fa0c..f1491b4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.UserManager;
 import android.service.autofill.Dataset;
+import android.service.autofill.FillContext;
 import android.service.autofill.FillResponse;
 import android.support.annotation.NonNull;
 import android.support.test.InstrumentationRegistry;
@@ -40,8 +41,10 @@
 
 import com.android.compatibility.common.util.SystemUtil;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 /**
  * Helper for common funcionalities.
@@ -163,6 +166,15 @@
     }
 
     /**
+     * Dump the contexts on logcat.
+     */
+    static void dumpStructure(String message, List<FillContext> contexts) {
+        for (FillContext context : contexts) {
+            dumpStructure(message, context.getStructure());
+        }
+    }
+
+    /**
      * Dumps the state of the autofill service on logcat.
      */
     static void dumpAutofillService() {
@@ -227,6 +239,19 @@
     /**
      * Gets a node given its Android resource id, or {@code null} if not found.
      */
+    static ViewNode findNodeByResourceId(ArrayList<FillContext> contexts, String resourceId) {
+        for (FillContext context : contexts) {
+            ViewNode node = findNodeByResourceId(context.getStructure(), resourceId);
+            if (node != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets a node given its Android resource id, or {@code null} if not found.
+     */
     static ViewNode findNodeByResourceId(ViewNode node, String resourceId) {
         if (resourceId.equals(node.getIdEntry())) {
             return node;
@@ -530,15 +555,15 @@
      * Creates an array of {@link AutofillId} mapped from the {@code structure} nodes with the given
      * {@code resourceIds}.
      */
-    static AutofillId[] getAutofillIds(AssistStructure structure, String[] resourceIds) {
+    static AutofillId[] getAutofillIds(Function<String, ViewNode> nodeResolver,
+            String[] resourceIds) {
         if (resourceIds == null) return null;
 
         final AutofillId[] requiredIds = new AutofillId[resourceIds.length];
         for (int i = 0; i < resourceIds.length; i++) {
             final String resourceId = resourceIds[i];
-            final ViewNode node = findNodeByResourceId(structure, resourceId);
+            final ViewNode node = nodeResolver.apply(resourceId);
             if (node == null) {
-                dumpStructure("getAutofillIds()", structure);
                 throw new AssertionError("No node with savable resourceId " + resourceId);
             }
             requiredIds[i] = node.getAutofillId();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
index 44ca039..61b47af 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
@@ -38,6 +38,7 @@
 import android.service.autofill.SaveCallback;
 import android.util.Log;
 
+import java.util.ArrayList;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -85,21 +86,17 @@
     @Override
     public void onFillRequest(android.service.autofill.FillRequest request,
             CancellationSignal cancellationSignal, FillCallback callback) {
-        final AssistStructure structure = request.getStructure();
-        if (DUMP_FILL_REQUESTS) dumpStructure("onFillRequest()", structure);
+        if (DUMP_FILL_REQUESTS) dumpStructure("onFillRequest()", request.getFillContexts());
 
-        sReplier.onFillRequest(structure, request.getClientState(), cancellationSignal, callback,
-                request.getFlags());
+        sReplier.onFillRequest(request.getFillContexts(), request.getClientState(),
+                cancellationSignal, callback, request.getFlags());
     }
 
     @Override
     public void onSaveRequest(android.service.autofill.SaveRequest request,
             SaveCallback callback) {
-        final List<FillContext> contexts = request.getFillContexts();
-        final AssistStructure structure = contexts.get(contexts.size() - 1).getStructure();
-
-        if (DUMP_SAVE_REQUESTS) dumpStructure("onSaveRequest()", structure);
-        sReplier.onSaveRequest(structure, request.getClientState(), callback);
+        if (DUMP_SAVE_REQUESTS) dumpStructure("onSaveRequest()", request.getFillContexts());
+        sReplier.onSaveRequest(request.getFillContexts(), request.getClientState(), callback);
     }
 
     /**
@@ -152,18 +149,20 @@
      */
     static final class FillRequest {
         final AssistStructure structure;
+        final ArrayList<FillContext> contexts;
         final Bundle data;
         final CancellationSignal cancellationSignal;
         final FillCallback callback;
         final int flags;
 
-        private FillRequest(AssistStructure structure, Bundle data,
+        private FillRequest(ArrayList<FillContext> contexts, Bundle data,
                 CancellationSignal cancellationSignal, FillCallback callback, int flags) {
-            this.structure = structure;
+            this.contexts = contexts;
             this.data = data;
             this.cancellationSignal = cancellationSignal;
             this.callback = callback;
             this.flags = flags;
+            structure = contexts.get(contexts.size() - 1).getStructure();
         }
     }
 
@@ -173,12 +172,18 @@
      * that can be asserted at the end of a test case.
      */
     static final class SaveRequest {
+        final List<FillContext> contexts;
         final AssistStructure structure;
         final Bundle data;
         final SaveCallback callback;
 
-        private SaveRequest(AssistStructure structure, Bundle data, SaveCallback callback) {
-            this.structure = structure;
+        private SaveRequest(List<FillContext> contexts, Bundle data, SaveCallback callback) {
+            if (contexts != null && contexts.size() > 0) {
+                structure = contexts.get(contexts.size() - 1).getStructure();
+            } else {
+                structure = null;
+            }
+            this.contexts = contexts;
             this.data = data;
             this.callback = callback;
         }
@@ -277,7 +282,7 @@
             mSaveRequests.clear();
         }
 
-        private void onFillRequest(AssistStructure structure, Bundle data,
+        private void onFillRequest(ArrayList<FillContext> contexts, Bundle data,
                 CancellationSignal cancellationSignal, FillCallback callback, int flags) {
             try {
                 CannedFillResponse response = null;
@@ -288,7 +293,7 @@
                     Thread.currentThread().interrupt();
                 }
                 if (response == null) {
-                    dumpStructure("onFillRequest() without response", structure);
+                    dumpStructure("onFillRequest() without response", contexts);
                     throw new IllegalStateException("No CannedResponse");
                 }
                 if (response == NO_RESPONSE) {
@@ -296,19 +301,20 @@
                     return;
                 }
 
-                final FillResponse fillResponse = response.asFillResponse(structure);
+                final FillResponse fillResponse = response.asFillResponse(
+                        (id) -> Helper.findNodeByResourceId(contexts, id));
 
                 Log.v(TAG, "onFillRequest(): fillResponse = " + fillResponse);
                 callback.onSuccess(fillResponse);
             } finally {
-                mFillRequests.offer(new FillRequest(structure, data, cancellationSignal, callback,
+                mFillRequests.offer(new FillRequest(contexts, data, cancellationSignal, callback,
                         flags));
             }
         }
 
-        private void onSaveRequest(AssistStructure structure, Bundle data, SaveCallback callback) {
+        private void onSaveRequest(List<FillContext> contexts, Bundle data, SaveCallback callback) {
             Log.d(TAG, "onSaveRequest()");
-            mSaveRequests.offer(new SaveRequest(structure, data, callback));
+            mSaveRequests.offer(new SaveRequest(contexts, data, callback));
             callback.onSuccess();
         }
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 30cfde7..74356fa 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -62,6 +62,7 @@
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.service.autofill.FillEventHistory;
+import android.service.autofill.SaveInfo;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.uiautomator.UiObject2;
 import android.view.View;
@@ -1146,7 +1147,7 @@
     }
 
     @Test
-    public void testCustomNegativeSaveButton() throws Exception {
+    public void testRejectStyleNegativeSaveButton() throws Exception {
         enableService();
 
         // Set service behavior.
@@ -1159,7 +1160,7 @@
 
         sReplier.addResponse(new CannedFillResponse.Builder()
                 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
-                .setNegativeAction("Foo", listener)
+                .setNegativeAction(SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT, listener)
                 .build());
 
         // Trigger auto-fill.
@@ -1185,7 +1186,8 @@
         }, intentFilter);
 
         // Trigger the negative button.
-        sUiBot.saveForAutofill(false, SAVE_DATA_TYPE_PASSWORD);
+        sUiBot.saveForAutofill(SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT,
+                false, SAVE_DATA_TYPE_PASSWORD);
 
         // Wait for the custom action.
         assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
@@ -1194,6 +1196,55 @@
     }
 
     @Test
+    public void testCancelStyleNegativeSaveButton() throws Exception {
+        enableService();
+
+        // Set service behavior.
+
+        final String intentAction = "android.autofillservice.cts.CUSTOM_ACTION";
+
+        // Configure the save UI.
+        final IntentSender listener = PendingIntent.getBroadcast(
+                getContext(), 0, new Intent(intentAction), 0).getIntentSender();
+
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+                .setNegativeAction(SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL, listener)
+                .build());
+
+        // Trigger auto-fill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Wait for onFill() before proceeding.
+        sReplier.getNextFillRequest();
+
+        // Trigger save.
+        mActivity.onUsername((v) -> v.setText("foo"));
+        mActivity.onPassword((v) -> v.setText("foo"));
+        mActivity.tapLogin();
+
+        // Start watching for the negative intent
+        final CountDownLatch latch = new CountDownLatch(1);
+        final IntentFilter intentFilter = new IntentFilter(intentAction);
+        getContext().registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                getContext().unregisterReceiver(this);
+                latch.countDown();
+            }
+        }, intentFilter);
+
+        // Trigger the negative button.
+        sUiBot.saveForAutofill(SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL,
+                false, SAVE_DATA_TYPE_PASSWORD);
+
+        // Wait for the custom action.
+        assertThat(latch.await(500, TimeUnit.SECONDS)).isTrue();
+
+        assertNoDanglingSessions();
+    }
+
+    @Test
     public void testGetTextInputType() throws Exception {
         // Set service.
         enableService();
@@ -1253,13 +1304,17 @@
         assertThat(usernameContainer.getChildCount()).isEqualTo(2);
     }
 
+    private static final boolean BUG_36171235_FIXED = false;
+
+    @Test
     public void testAutofillManuallyOneDataset() throws Exception {
         // Set service.
         enableService();
 
+        if (BUG_36171235_FIXED)
         // And activity.
         mActivity.onUsername((v) -> {
-            // v.setAutofillMode(AUTOFILL_MODE_MANUAL);
+            v.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
             // TODO: setting an empty text, otherwise longPress() does not
             // display the AUTOFILL context menu. Need to fix it, but it's a test case issue...
             v.setText("");
@@ -1274,7 +1329,11 @@
         mActivity.expectAutoFill("dude", "sweet");
 
         // Long-press field to trigger AUTOFILL menu.
-        sUiBot.getAutofillMenuOption(ID_USERNAME).click();
+        if (BUG_36171235_FIXED) {
+            sUiBot.getAutofillMenuOption(ID_USERNAME).click();
+        } else {
+            mActivity.onUsername((v) -> mActivity.getAutofillManager().requestAutofill(v));
+        }
 
         final FillRequest fillRequest = sReplier.getNextFillRequest();
         assertThat(fillRequest.flags).isEqualTo(FLAG_MANUAL_REQUEST);
@@ -1286,10 +1345,12 @@
         mActivity.assertAutoFilled();
     }
 
+    @Test
     public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
         autofillManuallyTwoDatasets(true);
     }
 
+    @Test
     public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
         autofillManuallyTwoDatasets(false);
     }
@@ -1298,9 +1359,10 @@
         // Set service.
         enableService();
 
+        if (BUG_36171235_FIXED)
         // And activity.
         mActivity.onUsername((v) -> {
-            // v.setAutofillMode(AUTOFILL_MODE_MANUAL);
+            v.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
             // TODO: setting an empty text, otherwise longPress() does not display the AUTOFILL
             // context menu. Need to fix it, but it's a test case issue...
             v.setText("");
@@ -1327,7 +1389,11 @@
         }
 
         // Long-press field to trigger AUTOFILL menu.
-        sUiBot.getAutofillMenuOption(ID_USERNAME).click();
+        if (BUG_36171235_FIXED) {
+            sUiBot.getAutofillMenuOption(ID_USERNAME).click();
+        } else {
+            mActivity.onUsername((v) -> mActivity.getAutofillManager().requestAutofill(v));
+        }
 
         final FillRequest fillRequest = sReplier.getNextFillRequest();
         assertThat(fillRequest.flags).isEqualTo(FLAG_MANUAL_REQUEST);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
index 32844d4..026cf08 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
@@ -54,9 +54,11 @@
             if (structure != null) {
                 Parcelable result;
                 if (sResponse != null) {
-                    result = sResponse.asFillResponse(structure);
+                    result = sResponse.asFillResponse(
+                            (id) -> Helper.findNodeByResourceId(structure, id));
                 } else if (sDataset != null) {
-                    result = sDataset.asDataset(structure);
+                    result = sDataset.asDataset(
+                            (id) -> Helper.findNodeByResourceId(structure, id));
                 } else {
                     throw new IllegalStateException("no dataset or response");
                 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
index 76c8c70..d474dc8 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
@@ -24,8 +24,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.Bundle;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
+import android.view.autofill.AutofillValue;
 import android.widget.EditText;
 
 import org.junit.Before;
@@ -52,11 +56,17 @@
     public void loginOnTwoFragments() throws Exception {
         enableService();
         try {
-            // Set expectations.
+            Bundle clientState = new Bundle();
+            clientState.putString("key", "value1");
             sReplier.addResponse(new CannedFillResponse.Builder()
-                    .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, "editText1").build());
+                    .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                            .setField("editText1", "editText1-autofilled")
+                            .setPresentation(createPresentation("dataset1"))
+                            .build())
+                    .setExtras(clientState)
+                    .build());
 
-            final InstrumentedAutoFillService.FillRequest[] request =
+            final InstrumentedAutoFillService.FillRequest[] fillRequest =
                     new InstrumentedAutoFillService.FillRequest[1];
 
             // Trigger autofill
@@ -67,37 +77,123 @@
                 });
 
                 try {
-                    request[0] = sReplier.getNextFillRequest();
+                    fillRequest[0] = sReplier.getNextFillRequest();
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
             }, (int) (FILL_TIMEOUT_MS * 2));
 
-            assertThat(findNodeByResourceId(request[0].structure, "editText1")).isNotNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText2")).isNotNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText3")).isNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText4")).isNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText5")).isNull();
+            assertThat(fillRequest[0].data).isNull();
 
-            Log.i(LOG_TAG, "Switching Fragments");
+            AssistStructure structure = fillRequest[0].contexts.get(0).getStructure();
+            assertThat(fillRequest[0].contexts.size()).isEqualTo(1);
+            assertThat(findNodeByResourceId(structure, "editText1")).isNotNull();
+            assertThat(findNodeByResourceId(structure, "editText2")).isNotNull();
+            assertThat(findNodeByResourceId(structure, "editText3")).isNull();
+            assertThat(findNodeByResourceId(structure, "editText4")).isNull();
+            assertThat(findNodeByResourceId(structure, "editText5")).isNull();
+
+            // Wait until autofill has been applied
+            sUiBot.selectDataset("dataset1");
+            sUiBot.assertShownByText("editText1-autofilled");
+
+            // Manually fill view
+            mActivity.syncRunOnUiThread(() -> mEditText2.setText("editText2-manually-filled"));
 
             // Replacing the fragment focused a previously unknown view which triggers a new
             // partition
+            clientState.putString("key", "value2");
             sReplier.addResponse(new CannedFillResponse.Builder()
-                    .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, "editText3").build());
+                    .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                            .setField("editText3", "editText3-autofilled")
+                            .setField("editText4", "editText4-autofilled")
+                            .setPresentation(createPresentation("dataset2"))
+                            .build())
+                    .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, "editText2", "editText5")
+                    .setExtras(clientState)
+                    .build());
 
+            Log.i(LOG_TAG, "Switching Fragments");
             mActivity.syncRunOnUiThread(
                     () -> mActivity.getFragmentManager().beginTransaction().replace(
                             R.id.rootContainer, new FragmentWithMoreEditTexts(),
                             FRAGMENT_TAG).commitNow());
+            EditText mEditText5 = mActivity.findViewById(R.id.editText5);
 
-            request[0] = sReplier.getNextFillRequest();
+            fillRequest[0] = sReplier.getNextFillRequest();
 
-            assertThat(findNodeByResourceId(request[0].structure, "editText1")).isNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText2")).isNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText3")).isNotNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText4")).isNotNull();
-            assertThat(findNodeByResourceId(request[0].structure, "editText5")).isNotNull();
+            // The fillRequest should have a fillContext for each partition. The first partition
+            // should be filled in
+            assertThat(fillRequest[0].contexts.size()).isEqualTo(2);
+
+            assertThat(fillRequest[0].data.getString("key")).isEqualTo("value1");
+
+            AssistStructure structure1 = fillRequest[0].contexts.get(0).getStructure();
+            ViewNode editText1Node = findNodeByResourceId(structure1, "editText1");
+            // The actual value in the structure is not updated in FillRequest-contexts, but the
+            // autofill value is. For text views in SaveRequest both are updated, but this is the
+            // only exception.
+            assertThat(editText1Node.getAutofillValue()).isEqualTo(
+                    AutofillValue.forText("editText1-autofilled"));
+
+            ViewNode editText2Node = findNodeByResourceId(structure1, "editText2");
+            // Manually filled fields are not send to onFill. They appear in onSave if they are set
+            // as saveable fields.
+            assertThat(editText2Node.getText().toString()).isEqualTo("");
+
+            assertThat(findNodeByResourceId(structure1, "editText3")).isNull();
+            assertThat(findNodeByResourceId(structure1, "editText4")).isNull();
+            assertThat(findNodeByResourceId(structure1, "editText5")).isNull();
+
+            AssistStructure structure2 = fillRequest[0].contexts.get(1).getStructure();
+
+            assertThat(findNodeByResourceId(structure2, "editText1")).isNull();
+            assertThat(findNodeByResourceId(structure2, "editText2")).isNull();
+            assertThat(findNodeByResourceId(structure2, "editText3")).isNotNull();
+            assertThat(findNodeByResourceId(structure2, "editText4")).isNotNull();
+            assertThat(findNodeByResourceId(structure2, "editText5")).isNotNull();
+
+            // Wait until autofill has been applied
+            sUiBot.selectDataset("dataset2");
+            sUiBot.assertShownByText("editText3-autofilled");
+            sUiBot.assertShownByText("editText4-autofilled");
+
+            // Manually fill view
+            mActivity.syncRunOnUiThread(() -> mEditText5.setText("editText5-manually-filled"));
+
+            // Finish activity and save data
+            mActivity.finish();
+            sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+
+            // The saveRequest should have a fillContext for each partition with all the data
+            InstrumentedAutoFillService.SaveRequest saveRequest = sReplier.getNextSaveRequest();
+            assertThat(saveRequest.contexts.size()).isEqualTo(2);
+
+            assertThat(saveRequest.data.getString("key")).isEqualTo("value2");
+
+            structure1 = saveRequest.contexts.get(0).getStructure();
+            editText1Node = findNodeByResourceId(structure1, "editText1");
+            assertThat(editText1Node.getText().toString()).isEqualTo("editText1-autofilled");
+
+            editText2Node = findNodeByResourceId(structure1, "editText2");
+            assertThat(editText2Node.getText().toString()).isEqualTo("editText2-manually-filled");
+
+            assertThat(findNodeByResourceId(structure1, "editText3")).isNull();
+            assertThat(findNodeByResourceId(structure1, "editText4")).isNull();
+            assertThat(findNodeByResourceId(structure1, "editText5")).isNull();
+
+            structure2 = saveRequest.contexts.get(1).getStructure();
+            assertThat(findNodeByResourceId(structure2, "editText1")).isNull();
+            assertThat(findNodeByResourceId(structure2, "editText2")).isNull();
+
+            ViewNode editText3Node = findNodeByResourceId(structure2, "editText3");
+            assertThat(editText3Node.getText().toString()).isEqualTo("editText3-autofilled");
+
+            ViewNode editText4Node = findNodeByResourceId(structure2, "editText4");
+            assertThat(editText4Node.getText().toString()).isEqualTo("editText4-autofilled");
+
+            ViewNode editText5Node = findNodeByResourceId(structure2, "editText5");
+            assertThat(editText5Node.getText().toString()).isEqualTo("editText5-manually-filled");
         } finally {
             disableService();
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 3b8c12a..fa7780a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -31,6 +31,7 @@
 import android.app.UiAutomation;
 import android.content.res.Resources;
 import android.os.SystemClock;
+import android.service.autofill.SaveInfo;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
@@ -249,6 +250,10 @@
     }
 
     UiObject2 assertSaveShowing(String description, int... types) {
+        return assertSaveShowing(SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL, description, types);
+    }
+
+    UiObject2 assertSaveShowing(int negativeButtonStyle, String description, int... types) {
         final UiObject2 snackbar = waitForObject(By.res("android", RESOURCE_ID_SAVE_SNACKBAR),
                 SAVE_TIMEOUT_MS);
 
@@ -288,6 +293,12 @@
             assertWithMessage("save subtitle(%s)", description).that(saveSubTitle).isNotNull();
         }
 
+        final String negativeButtonText = (negativeButtonStyle
+                == SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT) ? "NOT NOW" : "NO THANKS";
+        UiObject2 negativeButton = snackbar.findObject(By.text(negativeButtonText));
+        assertWithMessage("negative button (%s)", negativeButtonText)
+                .that(negativeButton).isNotNull();
+
         final String expectedAccessibilityTitle =
                 getString(RESOURCE_STRING_SAVE_SNACKBAR_ACCESSIBILITY_TITLE);
         assertAccessibilityTitle(snackbar, expectedAccessibilityTitle);
@@ -302,7 +313,19 @@
      * @param types expected types of save info.
      */
     void saveForAutofill(boolean yesDoIt, int... types) {
-        final UiObject2 saveSnackBar = assertSaveShowing(null, types);
+        final UiObject2 saveSnackBar = assertSaveShowing(
+                SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL,null, types);
+        saveForAutofill(saveSnackBar, yesDoIt);
+    }
+
+    /**
+     * Taps an option in the save snackbar.
+     *
+     * @param yesDoIt {@code true} for 'YES', {@code false} for 'NO THANKS'.
+     * @param types expected types of save info.
+     */
+    void saveForAutofill(int negativeButtonStyle, boolean yesDoIt, int... types) {
+        final UiObject2 saveSnackBar = assertSaveShowing(negativeButtonStyle,null, types);
         saveForAutofill(saveSnackBar, yesDoIt);
     }
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
index 670832c..2102773 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
@@ -41,7 +41,6 @@
 import android.view.autofill.AutofillValue;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -161,7 +160,8 @@
     @Override
     public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
         if (mOverrideDispatchProvideAutofillStructure) {
-            Log.d(TAG, "Overriding dispatchProvideAutofillStructure");
+            Log.d(TAG, "Overriding dispatchProvideAutofillStructure()");
+            structure.setAutofillId(getAutofillId());
             onProvideAutofillVirtualStructure(structure, flags);
         } else {
             super.dispatchProvideAutofillStructure(structure, flags);
@@ -184,7 +184,7 @@
             final ViewStructure child = mSync
                     ? structure.newChild(index)
                     : structure.asyncNewChild(index);
-            child.setAutofillId(structure, item.id);
+            child.setAutofillId(structure.getAutofillId(), item.id);
             child.setDataIsSensitive(item.sensitive);
             index++;
             final String className = item.editable ? TEXT_CLASS : LABEL_CLASS;
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index e4ca5af..ba902bf 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -296,5 +296,12 @@
     "android.telecom.cts.WiredHeadsetTest"
   ],
   bug: 26149528
+},
+{
+  desciption: "Seems to be failing on X86, flaky on arm. Root cause to be investigated",
+  names: [
+    "android.webkit.cts.WebViewClientTest#testOnRenderProcessGone"
+  ],
+  bug: 37704262
 }
 ]
diff --git a/tests/tests/app/AndroidManifest.xml b/tests/tests/app/AndroidManifest.xml
index be903e3..707b22b 100644
--- a/tests/tests/app/AndroidManifest.xml
+++ b/tests/tests/app/AndroidManifest.xml
@@ -23,6 +23,11 @@
 
         <activity android:name=".ApplyOverrideConfigurationActivity"
                   android:configChanges="orientation|screenSize" />
+
+        <activity android:name=".PictureInPictureActivity"
+                  android:resizeableActivity="false"
+                  android:supportsPictureInPicture="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/app/src/android/app/cts/PictureInPictureActionsTest.java b/tests/tests/app/src/android/app/cts/PictureInPictureActionsTest.java
index d08b29f..da02a81 100644
--- a/tests/tests/app/src/android/app/cts/PictureInPictureActionsTest.java
+++ b/tests/tests/app/src/android/app/cts/PictureInPictureActionsTest.java
@@ -15,12 +15,16 @@
  */
 package android.app.cts;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
-import android.app.ActivityManager;
+import android.app.Activity;
+import android.app.Instrumentation;
 import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -32,9 +36,20 @@
 @RunWith(AndroidJUnit4.class)
 public class PictureInPictureActionsTest {
 
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<PictureInPictureActivity> mActivityRule =
+            new ActivityTestRule<>(PictureInPictureActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+    }
+
     @Test
     public void testNumPictureInPictureActions() throws Exception {
-        // Currently enforce that there are a max of three actions
-        assertEquals(ActivityManager.getMaxNumPictureInPictureActions(), 3);
+        // Currently enforce that there are at least 3 actions
+        assertTrue(mActivity.getMaxNumPictureInPictureActions() >= 3);
     }
 }
diff --git a/tests/tests/app/src/android/app/cts/PictureInPictureActivity.java b/tests/tests/app/src/android/app/cts/PictureInPictureActivity.java
new file mode 100644
index 0000000..75245b7
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/PictureInPictureActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+package android.app.cts;
+
+import android.app.Activity;
+
+public class PictureInPictureActivity extends Activity {
+    // Empty
+}
diff --git a/tests/tests/app/src/android/app/cts/PictureInPictureParamsBuilderTest.java b/tests/tests/app/src/android/app/cts/PictureInPictureParamsBuilderTest.java
new file mode 100644
index 0000000..639c4d1
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/PictureInPictureParamsBuilderTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 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.app.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.PictureInPictureParams;
+import android.app.PictureInPictureParams.Builder;
+import android.graphics.Rect;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Rational;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+/**
+ * Tests the {@link PictureInPictureParams} builder.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PictureInPictureParamsBuilderTest {
+
+    @Test
+    public void testBuildParams() throws Exception {
+        // Set the params
+        Builder builder = new Builder()
+                .setAspectRatio(new Rational(1, 2))
+                .setActions(new ArrayList<>())
+                .setSourceRectHint(new Rect(0, 0, 100, 100));
+
+        PictureInPictureParams params = builder.build();
+        assertTrue(Float.compare(0.5f, params.getAspectRatio()) == 0);
+        assertTrue(params.getActions().isEmpty());
+        assertEquals(new Rect(0, 0, 100, 100), params.getSourceRectHint());
+
+        // Reset the params
+        builder.setAspectRatio(null)
+                .setActions(null)
+                .setSourceRectHint(null);
+        params = builder.build();
+
+        assertTrue(Float.compare(0f, params.getAspectRatio()) == 0);
+        assertNull(params.getActions());
+        assertNull(params.getSourceRectHint());
+    }
+}
diff --git a/tests/tests/content/res/values/attrs.xml b/tests/tests/content/res/values/attrs.xml
index 12b731b..236ee6c 100644
--- a/tests/tests/content/res/values/attrs.xml
+++ b/tests/tests/content/res/values/attrs.xml
@@ -49,6 +49,7 @@
     <attr name="type15" format="reference"/>
     <attr name="type16" format="string"/>
     <attr name="type17" format="reference|color"/>
+    <attr name="type18" format="reference|string"/>
     <attr name="typeEmpty" format="reference"/>
     <attr name="typeUndefined" format="reference"/>
     <declare-styleable name="style1">
@@ -69,6 +70,7 @@
         <attr name="type15"/>
         <attr name="type16"/>
         <attr name="type17"/>
+        <attr name="type18"/>
         <attr name="typeEmpty"/>
         <attr name="typeUndefined"/>
     </declare-styleable>
diff --git a/tests/tests/content/res/values/styles.xml b/tests/tests/content/res/values/styles.xml
index d1c30d7..b4db3ac 100644
--- a/tests/tests/content/res/values/styles.xml
+++ b/tests/tests/content/res/values/styles.xml
@@ -34,6 +34,7 @@
         <item name="type15">@array/difficultyLevel</item>
         <item name="type16">Typed Value!</item>
         <item name="type17">@color/testcolor_orientation</item>
+        <item name="type18">@font/samplefont</item>
         <item name="typeEmpty">@empty</item>
         <item name="typeUndefined">@null</item>
     </style>
@@ -181,4 +182,8 @@
     <style name="Theme_OrientationDependent">
         <item name="themeDimension">999px</item>
     </style>
+
+    <style name="Theme_InlineString">
+        <item name="testString">"This is a string"</item>
+    </style>
 </resources>
diff --git a/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java b/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
index b7a621f..24c61ae 100644
--- a/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
+++ b/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
@@ -83,6 +83,16 @@
     }
 
     @SmallTest
+    public void testObtainStyledAttributesWithInlineStringInTheme() {
+        mResTheme.applyStyle(R.style.Theme_InlineString, false);
+        final TypedArray ta = mResTheme.obtainStyledAttributes(new int[] { R.attr.testString });
+        assertNotNull(ta);
+        assertEquals(1, ta.length());
+        assertEquals(TypedValue.TYPE_STRING, ta.getType(0));
+        assertEquals("This is a string", ta.getString(0));
+    }
+
+    @SmallTest
     public void testResolveAttribute() {
         final TypedValue value = new TypedValue();
         getContext().getResources().getValue(R.raw.testmp3, value, true);
diff --git a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
index b31b446..5739554 100644
--- a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
+++ b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
@@ -25,6 +25,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.Typeface;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -48,9 +49,9 @@
     private static final String EXPECTED_TEXT = "TypedArray Test!";
     private static final String[] EXPECTED_TEXT_ARRAY = {"Easy", "Medium", "Hard"};
     private static final TypedValue DEF_VALUE = new TypedValue();
-    private static final int EXPECTED_INDEX_COUNT = 17;
+    private static final int EXPECTED_INDEX_COUNT = 18;
     private static final String EXPTECTED_POS_DESCRIP = "<internal>";
-    private static final int EXPECTED_LENGTH = 19;
+    private static final int EXPECTED_LENGTH = 20;
     private static final String EXPECTED_NON_RESOURCE_STRING = "testNonResourcesString";
     private static final String XML_BEGIN = "resources";
     private static final int EXPECTED_INT_ATT = 86400;
@@ -62,7 +63,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mTypedArray = getContext().getTheme().obtainStyledAttributes(R.style.Whatever, R.styleable.style1);
+        mTypedArray = getContext().getTheme()
+                .obtainStyledAttributes(R.style.Whatever, R.styleable.style1);
     }
 
     @Override
@@ -167,6 +169,9 @@
             actual_indices[idx] = attr_index;
         }
 
+        final Typeface font = t.getFont(R.styleable.style1_type18);
+        assertEquals(mContext.getResources().getFont(R.font.samplefont), font);
+
         // NOTE: order does not matter here.
         // R.styleable.style1_typeEmpty and R.styleable.style1_typeUndefined are not
         // expected because TYPE_NULL values do not get included in the index list.
@@ -187,7 +192,8 @@
                 R.styleable.style1_type14,
                 R.styleable.style1_type15,
                 R.styleable.style1_type16,
-                R.styleable.style1_type17);
+                R.styleable.style1_type17,
+                R.styleable.style1_type18);
     }
 
     public void testPeekValue() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
index a296659..e255f8e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
@@ -122,6 +122,18 @@
         assertSame(sRGB, cs);
     }
 
+    @Test
+    public void createDefaultColorSpace() {
+        ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
+        Bitmap.Config[] configs = new Bitmap.Config[] {
+                Bitmap.Config.ALPHA_8, Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888
+        };
+        for (Bitmap.Config config : configs) {
+            Bitmap bitmap = Bitmap.createBitmap(32, 32, config, true);
+            assertSame(sRGB, bitmap.getColorSpace());
+        }
+    }
+
     @Test(expected = IllegalArgumentException.class)
     public void createWithoutColorSpace() {
         Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, null);
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index a113afa..74f4549 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -51,6 +51,8 @@
 import android.text.SpannedString;
 import android.util.DisplayMetrics;
 
+import com.android.compatibility.common.util.ColorUtils;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Vector;
@@ -2179,4 +2181,18 @@
             Assert.fail();
         }
     }
+
+    @Test
+    public void testShadowLayer_paintColorPreserved() {
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        Paint paint = new Paint();
+
+        paint.setShadowLayer(5.0f, 10.0f, 10.0f, 0xFFFF0000);
+        paint.setColor(0xFF0000FF);
+        canvas.drawPaint(paint);
+
+        // Since the shadow is in the background, the canvas should be blue.
+        ColorUtils.verifyColor(0xFF0000FF, bitmap.getPixel(50, 50));
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
index 61d46b2..358e401 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
@@ -15,7 +15,9 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -97,5 +99,26 @@
         canvas.drawPoint(0, 0, paint);
         ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(0, 0));
     }
+
+    @Test
+    public void testGetColorMatrix() {
+        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(new ColorMatrix());
+        ColorMatrix getMatrix = new ColorMatrix();
+
+        filter.getColorMatrix(getMatrix);
+        assertEquals(new ColorMatrix(), getMatrix);
+
+        ColorMatrix scaleTranslate = new ColorMatrix(new float[] {
+                1, 0, 0, 0, 8,
+                0, 2, 0, 0, 7,
+                0, 0, 3, 0, 6,
+                0, 0, 0, 4, 5
+        });
+
+        filter = new ColorMatrixColorFilter(scaleTranslate);
+        filter.getColorMatrix(getMatrix);
+        assertEquals(scaleTranslate, getMatrix);
+        assertArrayEquals(scaleTranslate.getArray(), getMatrix.getArray(), 0);
+    }
 }
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
index 3f82150..fdbf92e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
@@ -435,12 +435,14 @@
 
         assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getSource());
         assertSame(ColorSpace.get(ColorSpace.Named.DCI_P3), connector.getDestination());
+        assertSame(ColorSpace.RenderIntent.PERCEPTUAL, connector.getRenderIntent());
 
         connector = ColorSpace.connect(
                 ColorSpace.get(ColorSpace.Named.SRGB),
                 ColorSpace.get(ColorSpace.Named.SRGB));
 
         assertSame(connector.getDestination(), connector.getSource());
+        assertSame(ColorSpace.RenderIntent.RELATIVE, connector.getRenderIntent());
 
         connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.DCI_P3));
         assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getDestination());
@@ -543,6 +545,7 @@
                 ColorSpace.get(ColorSpace.Named.SRGB));
 
         assertSame(connector.getSource(), connector.getDestination());
+        assertSame(ColorSpace.RenderIntent.RELATIVE, connector.getRenderIntent());
 
         float[] source = new float[] { 0.11112f, 0.22227f, 0.444448f };
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
index da2b934..c7befa8 100644
--- a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
@@ -35,6 +35,10 @@
 public class LightingColorFilterTest {
     private static final int TOLERANCE = 2;
 
+    private void verifyColor(int expected, int actual) {
+        ColorUtils.verifyColor(expected, actual, TOLERANCE);
+    }
+
     @Test
     public void testLightingColorFilter() {
         Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
@@ -86,7 +90,22 @@
         verifyColor(Color.argb(0x80, 30, 30, 30), bitmap.getPixel(0, 0));
     }
 
-    private void verifyColor(int expected, int actual) {
-        ColorUtils.verifyColor(expected, actual, TOLERANCE);
+    @Test
+    public void testGetColorAdd() {
+        LightingColorFilter filter = new LightingColorFilter(Color.WHITE, Color.BLACK);
+        ColorUtils.verifyColor(Color.BLACK, filter.getColorAdd());
+
+        filter = new LightingColorFilter(0x87654321, 0x12345678);
+        ColorUtils.verifyColor(0x12345678, filter.getColorAdd());
+    }
+
+
+    @Test
+    public void testGetColorMultiply() {
+        LightingColorFilter filter = new LightingColorFilter(Color.WHITE, Color.BLACK);
+        ColorUtils.verifyColor(Color.WHITE, filter.getColorMultiply());
+
+        filter = new LightingColorFilter(0x87654321, 0x12345678);
+        ColorUtils.verifyColor(0x87654321, filter.getColorMultiply());
     }
 }
diff --git a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
deleted file mode 100644
index bcecee1..0000000
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.cts;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecManager;
-import android.net.IpSecTransform;
-import android.os.ParcelFileDescriptor;
-import android.system.Os;
-import android.system.OsConstants;
-import android.test.AndroidTestCase;
-import java.io.ByteArrayOutputStream;
-import java.net.DatagramSocket;
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-
-public class IpSecManagerTest extends AndroidTestCase {
-
-    private static final String TAG = IpSecManagerTest.class.getSimpleName();
-
-    private IpSecManager mISM;
-
-    private ConnectivityManager mCM;
-
-    private static final InetAddress GOOGLE_DNS_4;
-    private static final InetAddress GOOGLE_DNS_6;
-
-    static {
-        try {
-            // Google Public DNS Addresses;
-            GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
-            GOOGLE_DNS_6 = InetAddress.getByName("2001:4860:4860::8888");
-        } catch (UnknownHostException e) {
-            throw new RuntimeException("Could not resolve DNS Addresses", e);
-        }
-    }
-
-    private static final InetAddress[] GOOGLE_DNS_LIST =
-            new InetAddress[] {GOOGLE_DNS_4, GOOGLE_DNS_6};
-
-    private static final int DROID_SPI = 0xD1201D;
-
-    private static final byte[] CRYPT_KEY =
-            new byte[] {
-                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
-                0x0E, 0x0F
-            };
-    private static final byte[] AUTH_KEY =
-            new byte[] {
-                0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x7F
-            };
-
-    protected void setUp() throws Exception {
-        super.setUp();
-        mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
-        mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE);
-    }
-
-    /*
-     * Allocate a random SPI
-     * Allocate a specific SPI using previous randomly created SPI value
-     * Realloc the same SPI that was specifically created (expect SpiUnavailable)
-     * Close SPIs
-     */
-    public void testAllocSpi() throws Exception {
-        for (InetAddress addr : GOOGLE_DNS_LIST) {
-            IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null;
-            randomSpi = mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_OUT, addr);
-            assertTrue(
-                    "Failed to receive a valid SPI",
-                    randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
-
-            droidSpi =
-                    mISM.reserveSecurityParameterIndex(
-                            IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
-            assertTrue(
-                    "Failed to allocate specified SPI, " + DROID_SPI,
-                    droidSpi.getSpi() == DROID_SPI);
-
-            try {
-                mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
-                fail("Duplicate SPI was allowed to be created");
-            } catch (IpSecManager.SpiUnavailableException expected) {
-                // This is a success case because we expect a dupe SPI to throw
-            }
-
-            randomSpi.close();
-            droidSpi.close();
-        }
-    }
-
-    /*
-     * Alloc outbound SPI
-     * Alloc inbound SPI
-     * Create transport mode transform
-     * open socket
-     * apply transform to socket
-     * send data on socket
-     * release transform
-     * send data (expect exception)
-     */
-    public void testCreateTransform() throws Exception {
-        InetAddress local = InetAddress.getLoopbackAddress();
-        IpSecManager.SecurityParameterIndex outSpi =
-                mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_OUT, local);
-
-        IpSecManager.SecurityParameterIndex inSpi =
-                mISM.reserveSecurityParameterIndex(
-                        IpSecTransform.DIRECTION_IN, local, outSpi.getSpi());
-
-        IpSecTransform transform =
-                new IpSecTransform.Builder(mContext)
-                        .setSpi(IpSecTransform.DIRECTION_OUT, outSpi)
-                        .setEncryption(
-                                IpSecTransform.DIRECTION_OUT,
-                                new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
-                        .setAuthentication(
-                                IpSecTransform.DIRECTION_OUT,
-                                new IpSecAlgorithm(
-                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
-                                        AUTH_KEY,
-                                        AUTH_KEY.length * 8))
-                        .setSpi(IpSecTransform.DIRECTION_IN, inSpi)
-                        .setEncryption(
-                                IpSecTransform.DIRECTION_IN,
-                                new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
-                        .setAuthentication(
-                                IpSecTransform.DIRECTION_IN,
-                                new IpSecAlgorithm(
-                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
-                                        AUTH_KEY,
-                                        CRYPT_KEY.length * 8))
-                        .buildTransportModeTransform(local);
-
-        // Hack to ensure the socket doesn't block indefinitely on failure
-        DatagramSocket localSocket = new DatagramSocket(8888);
-        localSocket.setSoTimeout(500);
-        ParcelFileDescriptor pin = ParcelFileDescriptor.fromDatagramSocket(localSocket);
-        FileDescriptor udpSocket = pin.getFileDescriptor();
-
-        mISM.applyTransportModeTransform(udpSocket, transform);
-        byte[] data = new String("Best test data ever!").getBytes("UTF-8");
-
-        byte[] in = new byte[data.length];
-        Os.sendto(udpSocket, data, 0, data.length, 0, local, 8888);
-        Os.read(udpSocket, in, 0, in.length);
-        assertTrue("Encapsulated data did not match.", Arrays.equals(data, in));
-        mISM.removeTransportModeTransform(udpSocket, transform);
-        Os.close(udpSocket);
-        transform.close();
-    }
-}
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index d489a6a..c9650bd 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -33,6 +33,7 @@
 
 import junit.framework.TestCase;
 
+import static android.os.Build.VERSION.CODENAME;
 import static android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
 
 public class BuildTest extends TestCase {
@@ -223,21 +224,7 @@
         assertTrue(TYPE_PATTERN.matcher(Build.TYPE).matches());
 
         assertNotEmpty(Build.USER);
-    }
 
-    public void testBuildConstants_forPrereleaseOrRelease() {
-        checkBuildConstants(CUR_DEVELOPMENT);
-    }
-
-    @RestrictedBuildTest // Expected to fail on prelease/dev builds, http://b/35922665
-    public void testBuildConstants_forRelease() {
-        checkBuildConstants(CUR_DEVELOPMENT - 1);
-    }
-
-    /**
-     * @param maxAllowedValue the maximum permitted value for constants other than CUR_DEVELOPMENT
-     */
-    private static void checkBuildConstants(int maxAllowedValue) {
         // CUR_DEVELOPMENT must be larger than any released version.
         Field[] fields = Build.VERSION_CODES.class.getDeclaredFields();
         for (Field field : fields) {
@@ -253,9 +240,12 @@
                     // It should be okay to change the value of this constant in future, but it
                     // should at least be a conscious decision.
                     assertEquals(10000, fieldValue);
+                } else if (fieldName.equals(CODENAME) && !CODENAME.equals("REL")) {
+                    // This is the current development version.
+                    assertEquals(CUR_DEVELOPMENT, fieldValue);
                 } else {
-                    assertTrue("Expected " + fieldName + " value to be <= " + maxAllowedValue
-                            + ", got " + fieldValue, fieldValue <= maxAllowedValue);
+                    assertTrue("Expected " + fieldName + " value to be < " + CUR_DEVELOPMENT
+                            + ", got " + fieldValue, fieldValue < CUR_DEVELOPMENT);
                 }
             }
         }
diff --git a/tests/tests/graphics/src/android/graphics/fonts/cts/FontRequestTest.java b/tests/tests/provider/src/android/provider/cts/FontRequestTest.java
similarity index 62%
rename from tests/tests/graphics/src/android/graphics/fonts/cts/FontRequestTest.java
rename to tests/tests/provider/src/android/provider/cts/FontRequestTest.java
index 1b00975..d9b8a7f 100644
--- a/tests/tests/graphics/src/android/graphics/fonts/cts/FontRequestTest.java
+++ b/tests/tests/provider/src/android/provider/cts/FontRequestTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.graphics.fonts.cts;
+package android.provider.cts;
 
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
@@ -22,7 +22,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import android.graphics.fonts.FontRequest;
+import android.provider.FontRequest;
 import android.os.Parcel;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -35,7 +35,7 @@
 import java.util.List;
 
 /**
- * Tests for {@link android.graphics.fonts.FontRequest}.
+ * Tests for {@link android.provider.FontRequest}.
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -47,46 +47,6 @@
             Base64.decode("e04fd020ea3a6910a2d808002b30", Base64.DEFAULT);
     private static final List<List<byte[]>> CERTS = Arrays.asList(Arrays.asList(BYTE_ARRAY));
 
-    @Test
-    public void testWriteToParcel() {
-        // GIVEN a FontRequest created with the long constructor
-        FontRequest request = new FontRequest(PROVIDER, PACKAGE, QUERY, CERTS);
-
-        // WHEN we write it to a Parcel
-        Parcel dest = Parcel.obtain();
-        request.writeToParcel(dest, 0);
-        dest.setDataPosition(0);
-
-        // THEN we create from that parcel and get the same values.
-        FontRequest result = FontRequest.CREATOR.createFromParcel(dest);
-        assertEquals(PROVIDER, result.getProviderAuthority());
-        assertEquals(PACKAGE, result.getProviderPackage());
-        assertEquals(QUERY, result.getQuery());
-        assertEquals(CERTS.size(), result.getCertificates().size());
-        List<byte[]> cert = CERTS.get(0);
-        List<byte[]> resultCert = result.getCertificates().get(0);
-        assertEquals(cert.size(), resultCert.size());
-        assertTrue(Arrays.equals(cert.get(0), resultCert.get(0)));
-    }
-
-    @Test
-    public void testWriteToParcel_shortConstructor() {
-        // GIVEN a FontRequest created with the short constructor
-        FontRequest request = new FontRequest(PROVIDER, PACKAGE, QUERY);
-
-        // WHEN we write it to a Parcel
-        Parcel dest = Parcel.obtain();
-        request.writeToParcel(dest, 0);
-        dest.setDataPosition(0);
-
-        // THEN we create from that parcel and get the same values.
-        FontRequest result = FontRequest.CREATOR.createFromParcel(dest);
-        assertEquals(PROVIDER, result.getProviderAuthority());
-        assertEquals(PACKAGE, result.getProviderPackage());
-        assertEquals(QUERY, result.getQuery());
-        assertNotNull(result.getCertificates());
-        assertEquals(0, result.getCertificates().size());
-    }
 
     @Test(expected = NullPointerException.class)
     public void testShortConstructor_nullAuthority() {
diff --git a/tests/tests/provider/src/android/provider/cts/FontsContractTest.java b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
index 472aed8..745a490 100644
--- a/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
+++ b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
@@ -29,8 +29,8 @@
 import android.content.pm.PackageInfo;
 import android.content.Context;
 import android.graphics.Typeface;
-import android.graphics.fonts.FontRequest;
 import android.graphics.fonts.FontVariationAxis;
+import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.provider.FontsContract.FontFamilyResult;
 import android.provider.FontsContract.FontInfo;
diff --git a/tests/tests/security/res/raw/bug_34097672.mp4 b/tests/tests/security/res/raw/bug_34097672.mp4
new file mode 100644
index 0000000..79acdf4
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_34097672.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_34360591.mp4 b/tests/tests/security/res/raw/bug_34360591.mp4
new file mode 100644
index 0000000..28c47d3
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_34360591.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index f120426..031b9f7 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -73,6 +73,10 @@
      before any existing test methods
      ***********************************************************/
 
+    public void testStagefright_bug_34360591() throws Exception {
+        doStagefrightTest(R.raw.bug_34360591);
+    }
+
     public void testStagefright_bug_35763994() throws Exception {
         doStagefrightTest(R.raw.bug_35763994);
     }
@@ -183,6 +187,11 @@
      ***********************************************************/
 
     @SecurityTest
+    public void testStagefright_bug_34097672() throws Exception {
+        doStagefrightTest(R.raw.bug_34097672);
+    }
+
+    @SecurityTest
     public void testStagefright_bug_33818508() throws Exception {
         doStagefrightTest(R.raw.bug_33818508);
     }
diff --git a/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
index 2cc8993..c40c0fd 100644
--- a/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
@@ -143,7 +143,7 @@
 
     @UiThreadTest
     @Before
-    public void setup() {
+    public void setup() throws Throwable {
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mActivity = mActivityRule.getActivity();
         mSearchView = (SearchView) mActivity.findViewById(R.id.search_view);
@@ -154,14 +154,16 @@
         // Use an adapter with our custom layout for each entry. The adapter "maps"
         // the content of the text column of our cursor to the @id/text1 view in the
         // layout.
-        mSuggestionsAdapter = new SimpleCursorAdapter(
-                mActivity,
-                R.layout.searchview_suggestion_item,
-                null,
-                new String[] { TEXT_COLUMN_NAME },
-                new int[] { android.R.id.text1 },
-                CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
-        mSearchView.setSuggestionsAdapter(mSuggestionsAdapter);
+        mActivityRule.runOnUiThread(() -> {
+            mSuggestionsAdapter = new SimpleCursorAdapter(
+                    mActivity,
+                    R.layout.searchview_suggestion_item,
+                    null,
+                    new String[] { TEXT_COLUMN_NAME },
+                    new int[] { android.R.id.text1 },
+                    CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
+            mSearchView.setSuggestionsAdapter(mSuggestionsAdapter);
+        });
     }
 
     @UiThreadTest
diff --git a/tools/cts-tradefed/res/config/cts-sts.xml b/tools/cts-tradefed/res/config/security-bulletin.xml
similarity index 95%
rename from tools/cts-tradefed/res/config/cts-sts.xml
rename to tools/cts-tradefed/res/config/security-bulletin.xml
index 8e4c030..02175a9 100644
--- a/tools/cts-tradefed/res/config/cts-sts.xml
+++ b/tools/cts-tradefed/res/config/security-bulletin.xml
@@ -15,7 +15,7 @@
 -->
 <configuration description="Runs Security Patch test cases">
 
-    <option name="plan" value="cts-sts" />
+    <option name="plan" value="security-bulletin" />
 
     <include name="cts"/>
 
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index 7e9c304..f84f2ec 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -95,7 +95,7 @@
 
         /* run sepolicy-analyze neverallow check on policy file using given neverallow rules */
         ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
-                devicePolicyFile.getAbsolutePath(), "neverallow", "-n",
+                devicePolicyFile.getAbsolutePath(), "neverallow", "-w", "-n",
                 neverallowRule);
         pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
         pb.redirectErrorStream(true);