Merge "Allow permissions to be denied" into oc-mr1-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index dc9d1c1..c867649 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1066,6 +1066,17 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
         </activity>
 
+        <activity android:name=".location.GnssPseudorangeVerificationTestsActivity"
+            android:label="@string/location_pseudorange_value_test"
+            android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_hardware"/>
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+        </activity>
+
         <activity android:name=".location.GnssTtffTestsActivity"
             android:label="@string/location_gnss_ttff_test"
             android:screenOrientation="locked">
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 9bff3b7..62f747d 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -557,6 +557,7 @@
     <string name="location_gnss_measure_no_location_test">GNSS Measurement Before Location Test</string>
     <string name="location_gnss_reg_test">GNSS Measurement Registration Test</string>
     <string name="location_gnss_value_test">GNSS Measurement Values Test</string>
+    <string name="location_pseudorange_value_test">GNSS Pseudorange Test</string>
     <string name="location_gnss_ttff_test">GNSS TTFF Test</string>
     <string name="location_gnss_nav_msg_test">GNSS Navigation Message Test</string>
     <string name="location_gnss_status_test">GNSS Status Test</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssPseudorangeVerificationTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssPseudorangeVerificationTestsActivity.java
new file mode 100644
index 0000000..e17b67a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssPseudorangeVerificationTestsActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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 com.android.cts.verifier.location;
+
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+import android.location.cts.GnssPseudorangeVerificationTest;
+
+/**
+ * Activity to execute CTS GnssPseudorangeVerificationTest.
+ * It is a wrapper for {@link GnssPseudorangeVerificationTest} running with AndroidJUnitRunner.
+ */
+
+public class GnssPseudorangeVerificationTestsActivity extends GnssCtsTestActivity {
+  public GnssPseudorangeVerificationTestsActivity() {
+    super(GnssPseudorangeVerificationTest.class);
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssStatusTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssStatusTestsActivity.java
index a64c5d3..b132c50 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssStatusTestsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssStatusTestsActivity.java
@@ -1,3 +1,19 @@
+/*
+ * 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 com.android.cts.verifier.location;
 
 import com.android.cts.verifier.location.base.GnssCtsTestActivity;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssTtffTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssTtffTestsActivity.java
index 1ba925c..7b5b6fb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssTtffTestsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssTtffTestsActivity.java
@@ -1,3 +1,19 @@
+/*
+ * 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.verifier.location;
 
 import com.android.cts.verifier.location.base.GnssCtsTestActivity;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/LocationListenerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/LocationListenerActivity.java
index 8140b3f..4db0b54 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/location/LocationListenerActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/LocationListenerActivity.java
@@ -1,3 +1,19 @@
+/*
+ * 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 com.android.cts.verifier.location;
 
 import android.app.Activity;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index e85119b..ce64254 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -558,9 +558,13 @@
         try {
             File logFile = null;
             if (mCompressLogs) {
-                logFile = mTestLogSaver.saveAndGZipLogData(name, type, stream.createInputStream());
+                try (InputStream inputStream = stream.createInputStream()) {
+                    logFile = mTestLogSaver.saveAndGZipLogData(name, type, inputStream);
+                }
             } else {
-                logFile = mTestLogSaver.saveLogData(name, type, stream.createInputStream());
+                try (InputStream inputStream = stream.createInputStream()) {
+                    logFile = mTestLogSaver.saveLogData(name, type, inputStream);
+                }
             }
             debug("Saved logs for %s in %s", name, logFile.getAbsolutePath());
         } catch (IOException e) {
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/src/com/android/cts/permission/policy/PermissionPolicyTest25.java b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/src/com/android/cts/permission/policy/PermissionPolicyTest25.java
index aa09990..2db1f41 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/src/com/android/cts/permission/policy/PermissionPolicyTest25.java
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/src/com/android/cts/permission/policy/PermissionPolicyTest25.java
@@ -67,9 +67,9 @@
             flagsToString += flagsToString.isEmpty() ? "runtimeOnly" : "|runtimeOnly";
             protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY;
         }
-        if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) != 0) {
+        if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0) {
             flagsToString += flagsToString.isEmpty() ? "ephemeral" : "|ephemeral";
-            protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_EPHEMERAL;
+            protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
         }
         if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
             flagsToString += flagsToString.isEmpty() ? "appop" : "|appop";
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
index d24fbdb..27d6c64 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
@@ -81,7 +81,7 @@
      * Same as {@link #testConfigurationUpdatesWhenResizedFromFullscreen()} but resizing
      * from docked state to fullscreen (reverse).
      */
-    // TODO: Flaky, add to presubmit when b/63404575 is fixed.
+    @Presubmit
     public void testConfigurationUpdatesWhenResizedFromDockedStack() throws Exception {
         if (!supportsSplitScreenMultiWindow()) {
             CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
@@ -118,7 +118,7 @@
      * Same as {@link #testConfigurationUpdatesWhenRotatingWhileFullscreen()} but when the Activity
      * is in the docked stack.
      */
-    // TODO: Flaky, add to presubmit when b/63404575 is fixed.
+    @Presubmit
     public void testConfigurationUpdatesWhenRotatingWhileDocked() throws Exception {
         if (!supportsSplitScreenMultiWindow()) {
             CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
index 8206fdf..f5a53d4 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -1125,7 +1125,7 @@
     /**
      * Test that all activities that were on the private display are destroyed on display removal.
      */
-    // TODO: Flaky, add to presubmit when b/63404575 is fixed.
+    @Presubmit
     public void testContentDestroyOnDisplayRemoved() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 4bb8fa6..7a33df0 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -65,6 +65,14 @@
         <activity android:name=".FragmentContainerActivity" />
         <activity android:name=".DuplicateIdActivity"
             android:theme="@android:style/Theme.NoTitleBar" />
+        <activity android:name=".SimpleSaveActivity">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
 
         <service
             android:name=".InstrumentedAutoFillService"
diff --git a/tests/autofillservice/res/layout/simple_save_activity.xml b/tests/autofillservice/res/layout/simple_save_activity.xml
new file mode 100644
index 0000000..ab3aa86b
--- /dev/null
+++ b/tests/autofillservice/res/layout/simple_save_activity.xml
@@ -0,0 +1,60 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal" >
+
+        <TextView
+            android:id="@+id/label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Label:" />
+        <EditText
+            android:id="@+id/input"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal" >
+
+        <Button
+            android:id="@+id/cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Cancel" />
+
+        <Button
+            android:id="@+id/commit"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Commit" />
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java
index 7cf3c64..88fd1e0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java
@@ -28,6 +28,10 @@
         super(activityClass);
     }
 
+    public AutofillActivityTestRule(Class<T> activityClass, boolean launchActivity) {
+        super(activityClass, false, launchActivity);
+    }
+
     @Override
     protected void beforeActivityLaunched() {
         Helper.preTestCleanup();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
index f5e7f87..84be355 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
@@ -74,6 +74,12 @@
     private FillExpectation mExpectation;
     private CountDownLatch mBuyLatch;
 
+    private static CheckoutActivity sInstance;
+
+    public CheckoutActivity() {
+        sInstance = this;
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -98,6 +104,12 @@
         mClearButton.setOnClickListener((v) -> resetFields());
     }
 
+    static void finishIt() {
+        if (sInstance != null) {
+            sInstance.finish();
+        }
+    }
+
     protected int getContentView() {
         return R.layout.checkout_activity;
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index 7d68e58..59b0b7c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -107,7 +107,7 @@
         final CharSequence[] options = ccExpirationNode.getAutofillOptions();
         assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
         assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
-                .containsExactly(
+                .containsExactly((Object [])
                         getContext().getResources().getStringArray(R.array.cc_expiration_values))
                 .inOrder();
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
index cec3886..38a8755 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
@@ -84,7 +84,7 @@
                 .setCustomDescription(descriptionBuilder.apply(usernameId, passwordId))
                 .build());
 
-        // Trigger auto-fill with custom description
+        // Trigger autofill with custom description
         mActivity.onPassword(View::requestFocus);
 
         // Wait for onFill() before proceeding.
@@ -224,6 +224,54 @@
         }, () -> assertSaveUiWithoutCustomDescriptionIsShown());
     }
 
+    private void multipleTransformationsForSameFieldTest(boolean matchFirst) throws Exception {
+        enableService();
+
+        // Set response with custom description
+        final AutofillId usernameId = mActivity.getUsername().getAutofillId();
+        final CharSequenceTransformation firstTrans = new CharSequenceTransformation
+                .Builder(usernameId, Pattern.compile("(marco)"), "polo")
+                .build();
+        final CharSequenceTransformation secondTrans = new CharSequenceTransformation
+                .Builder(usernameId, Pattern.compile("(MARCO)"), "POLO")
+                .build();
+        final RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                R.layout.two_horizontal_text_fields);
+        final CustomDescription customDescription = new CustomDescription.Builder(presentation)
+                .addChild(R.id.first, firstTrans)
+                .addChild(R.id.first, secondTrans)
+                .build();
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_USERNAME)
+                .setCustomDescription(customDescription)
+                .build());
+
+        // Trigger autofill with custom description
+        mActivity.onPassword(View::requestFocus);
+
+        // Wait for onFill() before proceeding.
+        sReplier.getNextFillRequest();
+
+        // Trigger save.
+        final String username = matchFirst ? "marco" : "MARCO";
+        mActivity.onUsername((v) -> v.setText(username));
+        mActivity.onPassword((v) -> v.setText(LoginActivity.BACKDOOR_PASSWORD_SUBSTRING));
+        mActivity.tapLogin();
+
+        final String expectedText = matchFirst ? "polo" : "POLO";
+        assertSaveUiWithCustomDescriptionIsShown(expectedText);
+    }
+
+    @Test
+    public void applyMultipleTransformationsForSameField_matchFirst() throws Exception {
+        multipleTransformationsForSameFieldTest(true);
+    }
+
+    @Test
+    public void applyMultipleTransformationsForSameField_matchSecond() throws Exception {
+        multipleTransformationsForSameFieldTest(false);
+    }
+
     private void assertSaveUiWithoutCustomDescriptionIsShown() {
         // First make sure the UI is shown...
         final UiObject2 saveUi = sUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DismissType.java b/tests/autofillservice/src/android/autofillservice/cts/DismissType.java
new file mode 100644
index 0000000..e8e7689
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/DismissType.java
@@ -0,0 +1,31 @@
+/*
+ * 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.autofillservice.cts;
+
+/**
+ * A simple enum for test cases where the Save UI is dismissed.
+ *
+ * <p><b>Note:</b> When new values are added to the enum, the equivalent tests must be added to
+ * both {@link LoginActivityTest} and {@link SimpleSaveActivityTest}.
+ */
+enum DismissType {
+    BACK_BUTTON,
+    HOME_BUTTON,
+    RECENTS_BUTTON,
+    TOUCH_OUTSIDE,
+    FOCUS_OUTSIDE,
+    LAUNCH_ACTIVITY
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index ea8feea..ffb76f7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -61,6 +61,8 @@
     static final String ID_LOGIN = "login";
     static final String ID_OUTPUT = "output";
 
+    private static final String CMD_LIST_SESSIONS = "cmd autofill list sessions";
+
     /**
      * Timeout (in milliseconds) until framework binds / unbinds from service.
      */
@@ -733,9 +735,17 @@
      * Asserts that there is no session left in the service.
      */
     public static void assertNoDanglingSessions() {
-        final String command = "cmd autofill list sessions";
-        final String result = runShellCommand(command);
-        assertWithMessage("Dangling sessions ('%s'): %s'", command, result).that(result).isEmpty();
+        final String result = runShellCommand(CMD_LIST_SESSIONS);
+        assertWithMessage("Dangling sessions ('%s'): %s'", CMD_LIST_SESSIONS, result).that(result)
+                .isEmpty();
+    }
+
+    /**
+     * Asserts that there is a pending session for the given package.
+     */
+    public static void assertHasSessions(String packageName) {
+        final String result = runShellCommand(CMD_LIST_SESSIONS);
+        assertThat(result).contains(packageName);
     }
 
     /**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
index 1206c62..2daf5bc 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
@@ -51,6 +51,7 @@
     static final String ID_USERNAME_CONTAINER = "username_container";
     static final String AUTHENTICATION_MESSAGE = "Authentication failed. D'OH!";
     static final String BACKDOOR_USERNAME = "LemmeIn";
+    static final String BACKDOOR_PASSWORD_SUBSTRING = "pass";
 
     private TextView mUsernameLabel;
     private EditText mUsernameEditText;
@@ -113,7 +114,7 @@
         final String password = mPasswordEditText.getText().toString();
         final boolean valid = username.equals(password)
                 || (TextUtils.isEmpty(username) && TextUtils.isEmpty(password))
-                || password.contains("pass")
+                || password.contains(BACKDOOR_PASSWORD_SUBSTRING)
                 || username.equals(BACKDOOR_USERNAME);
 
         if (valid) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 7bc0989..9b575ec 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -1181,12 +1181,6 @@
         assertNoDanglingSessions();
     }
 
-    enum DismissType {
-        BACK_BUTTON,
-        HOME_BUTTON,
-        TOUCH_OUTSIDE
-    }
-
     @Test
     public void testSaveGoesAwayWhenTappingHomeButton() throws Exception {
         saveGoesAway(DismissType.HOME_BUTTON);
@@ -1198,10 +1192,34 @@
     }
 
     @Test
+    public void testSaveGoesAwayWhenTappingRecentsButton() throws Exception {
+        // Launches new activity first...
+        startCheckoutActivityAsNewTask();
+        try {
+            // .. then the real activity being tested.
+            sUiBot.switchAppsUsingRecents();
+            sUiBot.assertShownByRelativeId(ID_USERNAME_CONTAINER);
+
+            saveGoesAway(DismissType.RECENTS_BUTTON);
+        } finally {
+            CheckoutActivity.finishIt();
+        }
+    }
+
+    @Test
     public void testSaveGoesAwayWhenTouchingOutside() throws Exception {
         saveGoesAway(DismissType.TOUCH_OUTSIDE);
     }
 
+    @Test
+    public void testSaveGoesAwayWhenLaunchingNewActivity() throws Exception {
+        try {
+            saveGoesAway(DismissType.LAUNCH_ACTIVITY);
+        } finally {
+            CheckoutActivity.finishIt();
+        }
+    }
+
     private void saveGoesAway(DismissType dismissType) throws Exception {
         enableService();
 
@@ -1243,6 +1261,13 @@
             case TOUCH_OUTSIDE:
                 sUiBot.assertShownByText(expectedMessage).click();
                 break;
+            case RECENTS_BUTTON:
+                sUiBot.switchAppsUsingRecents();
+                sUiBot.assertShownByRelativeId(CheckoutActivity.ID_ADDRESS);
+                break;
+            case LAUNCH_ACTIVITY:
+                startCheckoutActivityAsNewTask();
+                break;
             default:
                 throw new IllegalArgumentException("invalid dismiss type: " + dismissType);
         }
@@ -3157,6 +3182,7 @@
                 .isEqualTo(5);
     }
 
+    @Test
     public void testAutofillLargeNumberOfDatasets() throws Exception {
         // Set service.
         enableService();
@@ -3196,4 +3222,35 @@
 
         // TODO: once it supports scrolling, selects the last dataset and asserts it's filled.
     }
+
+    @Test
+    public void testCancellationSignalCalledAfterTimeout() throws Exception {
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        final OneTimeCancellationSignalListener listener =
+                new OneTimeCancellationSignalListener(Helper.FILL_TIMEOUT_MS + 2000);
+        sReplier.addResponse(DO_NOT_REPLY_RESPONSE);
+
+        // Trigger auto-fill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Attach listener to CancellationSignal.
+        waitUntilConnected();
+        sReplier.getNextFillRequest().cancellationSignal.setOnCancelListener(listener);
+
+        // AssertResults
+        waitUntilDisconnected();
+        listener.assertOnCancelCalled();
+    }
+
+    private void startCheckoutActivityAsNewTask() {
+        final Context context = getContext();
+        final Intent intent = new Intent(context, CheckoutActivity.class);
+        intent.setFlags(
+                Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
+        context.startActivity(intent);
+        sUiBot.assertShownByRelativeId(CheckoutActivity.ID_ADDRESS);
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OneTimeCancellationSignalListener.java b/tests/autofillservice/src/android/autofillservice/cts/OneTimeCancellationSignalListener.java
new file mode 100644
index 0000000..0b055e0
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/OneTimeCancellationSignalListener.java
@@ -0,0 +1,48 @@
+/*
+ * 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.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.os.CancellationSignal;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Custom {@link android.os.CancellationSignal.OnCancelListener} used to assert that
+ * {@link android.os.CancellationSignal.OnCancelListener} was called, and just once.
+ */
+final class OneTimeCancellationSignalListener implements CancellationSignal.OnCancelListener {
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+    private final long mTimeoutMs;
+
+    OneTimeCancellationSignalListener(long timeoutMs) {
+        mTimeoutMs = timeoutMs;
+    }
+
+    void assertOnCancelCalled() throws Exception {
+        final boolean called = mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS);
+        assertWithMessage("Timeout (%s ms) waiting for onCancel()", mTimeoutMs)
+                .that(called).isTrue();
+    }
+
+    @Override
+    public void onCancel() {
+        mLatch.countDown();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
index 3e39004..c82fa42 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
@@ -596,4 +596,88 @@
         // Assert the snack bar is not shown.
         sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_ADDRESS);
     }
+
+    @Test
+    public void testDontShowSaveUiWhenUserClearedAutofilledFieldThatIsRequired() throws Exception {
+        // Set service.
+        enableService();
+
+        mActivity.expectAutoFill("742 Evergreen Terrace", "Simpsons House",
+                "Springfield", "Yellow");
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_ADDRESS, ID_ADDRESS1, ID_ADDRESS2)
+                .setOptionalSavableIds(ID_CITY)
+                .addDataset(new CannedDataset.Builder()
+                        .setPresentation(createPresentation("SF"))
+                        .setField(ID_ADDRESS1, "742 Evergreen Terrace")
+                        .setField(ID_ADDRESS2, "Simpsons House")
+                        .setField(ID_CITY, "Springfield")
+                        .setField(ID_FAVORITE_COLOR, "Yellow")
+                        .build())
+                .build());
+
+        // Trigger autofill.
+        mActivity.syncRunOnUiThread(() -> mActivity.mAddress1.requestFocus());
+        sReplier.getNextFillRequest();
+
+        sUiBot.selectDataset("SF");
+        mActivity.assertAutoFilled();
+
+        // Clear the field.
+        mActivity.syncRunOnUiThread(() -> mActivity.mAddress2.setText(""));
+
+        // Trigger save...
+        mActivity.save();
+
+        // ...and make sure the snack bar is not shown.
+        sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_ADDRESS);
+    }
+
+    @Test
+    public void testShowSaveUiWhenUserClearedAutofilledFieldThatIsOptional() throws Exception {
+        // Set service.
+        enableService();
+
+        mActivity.expectAutoFill("742 Evergreen Terrace", "Simpsons House",
+                "Springfield", "Yellow");
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_ADDRESS, ID_ADDRESS1, ID_ADDRESS2)
+                .setOptionalSavableIds(ID_CITY)
+                .addDataset(new CannedDataset.Builder()
+                        .setPresentation(createPresentation("SF"))
+                        .setField(ID_ADDRESS1, "742 Evergreen Terrace")
+                        .setField(ID_ADDRESS2, "Simpsons House")
+                        .setField(ID_CITY, "Springfield")
+                        .setField(ID_FAVORITE_COLOR, "Yellow")
+                        .build())
+                .build());
+
+        // Trigger autofill.
+        mActivity.syncRunOnUiThread(() -> mActivity.mAddress1.requestFocus());
+        sReplier.getNextFillRequest();
+
+        sUiBot.selectDataset("SF");
+        mActivity.assertAutoFilled();
+
+        // Clear the field.
+        mActivity.syncRunOnUiThread(() -> mActivity.mCity.setText(""));
+
+        // Trigger save...
+        mActivity.save();
+
+        // ...and make sure the snack bar is shown.
+        sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_ADDRESS);
+
+        // Finally, assert values.
+        final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_ADDRESS1),
+                "742 Evergreen Terrace");
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_ADDRESS2),
+                "Simpsons House");
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_CITY), "");
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_FAVORITE_COLOR),
+                "Yellow");
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivity.java b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivity.java
new file mode 100644
index 0000000..163e9ea
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivity.java
@@ -0,0 +1,51 @@
+/*
+ * 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.autofillservice.cts;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+/**
+ * Simple activity that has an edit text and buttons to cancel or commit the autofill context.
+ */
+public class SimpleSaveActivity extends AbstractAutoFillActivity {
+
+    static final String ID_LABEL = "label";
+    static final String ID_INPUT = "input";
+    static final String TEXT_LABEL = "Label:";
+
+    TextView mLabel;
+    EditText mInput;
+    Button mCancel;
+    Button mCommit;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.simple_save_activity);
+
+        mLabel = findViewById(R.id.label);
+        mInput = findViewById(R.id.input);
+        mCancel = findViewById(R.id.cancel);
+        mCommit = findViewById(R.id.commit);
+
+        mCancel.setOnClickListener((v) -> getAutofillManager().cancel());
+        mCommit.setOnClickListener((v) -> getAutofillManager().commit());
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
new file mode 100644
index 0000000..5f7713c
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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.autofillservice.cts;
+
+import static android.autofillservice.cts.Helper.assertTextAndValue;
+import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
+import static android.autofillservice.cts.SimpleSaveActivity.ID_INPUT;
+import static android.autofillservice.cts.SimpleSaveActivity.TEXT_LABEL;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.uiautomator.UiObject2;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class SimpleSaveActivityTest extends AutoFillServiceTestCase {
+
+    @Rule
+    public final AutofillActivityTestRule<SimpleSaveActivity> mActivityRule =
+            new AutofillActivityTestRule<SimpleSaveActivity>(SimpleSaveActivity.class, false);
+
+    private SimpleSaveActivity mActivity;
+
+    // TODO: move mContext and mPackageName to superclass
+    private Context mContext;
+    private String mPackageName;
+
+    @Before
+    public void setFixtures() {
+        mContext = getContext();
+        mPackageName = mContext.getPackageName();
+    }
+
+    private void startActivity() {
+        mActivity =
+                mActivityRule.launchActivity(new Intent(getContext(), SimpleSaveActivity.class));
+    }
+
+    private void startActivity(boolean remainOnRecents) {
+        final Intent intent = new Intent(mContext, SimpleSaveActivity.class);
+        if (remainOnRecents) {
+            intent.setFlags(
+                    Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+        }
+        mActivity = mActivityRule.launchActivity(intent);
+    }
+
+    @Test
+    public void testSave() throws Exception {
+        saveTest(false);
+    }
+
+    @Test
+    public void testSave_afterRotation() throws Exception {
+        sUiBot.setScreenOrientation(UiBot.PORTRAIT);
+        try {
+            saveTest(true);
+        } finally {
+            sUiBot.setScreenOrientation(UiBot.PORTRAIT);
+        }
+    }
+
+    private void saveTest(boolean rotate) throws Exception {
+        startActivity();
+
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT)
+                .build());
+
+        // Trigger autofill.
+        mActivity.syncRunOnUiThread(() -> mActivity.mInput.requestFocus());
+        sReplier.getNextFillRequest();
+        Helper.assertHasSessions(mPackageName);
+
+        // Trigger save.
+        mActivity.syncRunOnUiThread(() -> {
+            mActivity.mInput.setText("108");
+            mActivity.mCommit.performClick();
+        });
+        UiObject2 saveUi = sUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+        if (rotate) {
+            // TODO(b/64309238): since the session is gone, a new one is created when rotated;
+            // it might make sense to change the code to avoid that, but we need to re-evaluate
+            // after the CustomDescription pending intent changes.
+            sReplier.addResponse(CannedFillResponse.NO_RESPONSE);
+
+            sUiBot.setScreenOrientation(UiBot.LANDSCAPE);
+            saveUi = sUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+            sReplier.getNextFillRequest();
+        }
+
+        // Save it...
+        sUiBot.saveForAutofill(saveUi, true);
+
+        // ... and assert results
+        final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_INPUT), "108");
+    }
+
+    @Test
+    public void testCancelPreventsSaveUiFromShowing() throws Exception {
+        startActivity();
+
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT)
+                .build());
+
+        // Trigger autofill.
+        mActivity.syncRunOnUiThread(() -> mActivity.mInput.requestFocus());
+        sReplier.getNextFillRequest();
+        Helper.assertHasSessions(mPackageName);
+
+        // Cancel session.
+        mActivity.getAutofillManager().cancel();
+        Helper.assertNoDanglingSessions();
+
+        // Trigger save.
+        mActivity.syncRunOnUiThread(() -> {
+            mActivity.mInput.setText("108");
+            mActivity.mCommit.performClick();
+        });
+
+        // Assert it's not showing.
+        sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC);
+    }
+
+    @Test
+    public void testDismissSave_byTappingBack() throws Exception {
+        startActivity();
+        dismissSaveTest(DismissType.BACK_BUTTON);
+    }
+
+    @Test
+    public void testDismissSave_byTappingHome() throws Exception {
+        startActivity();
+        dismissSaveTest(DismissType.HOME_BUTTON);
+    }
+
+    @Test
+    public void testDismissSave_byTouchingOutside() throws Exception {
+        startActivity();
+        dismissSaveTest(DismissType.TOUCH_OUTSIDE);
+    }
+
+    @Test
+    public void testDismissSave_byFocusingOutside() throws Exception {
+        startActivity();
+        dismissSaveTest(DismissType.FOCUS_OUTSIDE);
+    }
+
+    @Test
+    public void testDismissSave_byTappingRecents() throws Exception {
+        // Launches a different activity first.
+        startWelcomeActivityOnNewTask();
+
+        // Then launches the main activity.
+        startActivity(true);
+        sUiBot.assertShownByRelativeId(ID_INPUT);
+
+        // And finally test it..
+        dismissSaveTest(DismissType.RECENTS_BUTTON);
+    }
+
+    @Test
+    public void testDismissSave_byLaunchingNewActivity() throws Exception {
+        startActivity();
+        try {
+            dismissSaveTest(DismissType.LAUNCH_ACTIVITY);
+        } finally {
+            WelcomeActivity.finishIt();
+        }
+    }
+
+    private void dismissSaveTest(DismissType dismissType) throws Exception {
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT)
+                .build());
+
+        // Trigger autofill.
+        mActivity.syncRunOnUiThread(() -> mActivity.mInput.requestFocus());
+        sReplier.getNextFillRequest();
+        Helper.assertHasSessions(mPackageName);
+
+        // Trigger save.
+        mActivity.syncRunOnUiThread(() -> {
+            mActivity.mInput.setText("108");
+            mActivity.mCommit.performClick();
+        });
+        sUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+        // Then make sure it goes away when user doesn't want it..
+        switch (dismissType) {
+            case BACK_BUTTON:
+                sUiBot.pressBack();
+                break;
+            case HOME_BUTTON:
+                sUiBot.pressHome();
+                break;
+            case TOUCH_OUTSIDE:
+                sUiBot.assertShownByText(TEXT_LABEL).click();
+                break;
+            case FOCUS_OUTSIDE:
+                mActivity.syncRunOnUiThread(() -> mActivity.mLabel.requestFocus());
+                sUiBot.assertShownByText(TEXT_LABEL).click();
+                break;
+            case RECENTS_BUTTON:
+                sUiBot.switchAppsUsingRecents();
+                WelcomeActivity.assertShowingDefaultMessage(sUiBot);
+                break;
+            case LAUNCH_ACTIVITY:
+                startWelcomeActivityOnNewTask();
+                break;
+            default:
+                throw new IllegalArgumentException("invalid dismiss type: " + dismissType);
+        }
+        sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC);
+    }
+
+    private void startWelcomeActivityOnNewTask() throws Exception {
+        final Intent intent = new Intent(mContext, WelcomeActivity.class);
+        intent.setFlags(
+                Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+        mContext.startActivity(intent);
+        WelcomeActivity.assertShowingDefaultMessage(sUiBot);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 495b05c..b434149 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -32,6 +32,7 @@
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.content.res.Resources;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.SaveInfo;
 import android.support.test.InstrumentationRegistry;
@@ -209,6 +210,16 @@
     }
 
     /**
+     * Asserts the id is shown on the screen, using a resource id from the test package.
+     * @return
+     */
+    UiObject2 assertShownByRelativeId(String id) {
+        final UiObject2 obj = waitForObject(By.res(mPackageName, id));
+        assertThat(obj).isNotNull();
+        return obj;
+    }
+
+    /**
      * Gets the text set on a view.
      */
     String getTextById(String id) {
@@ -246,7 +257,7 @@
     }
 
     /**
-     * Presses the back button.
+     * Presses the Back button.
      */
     void pressBack() {
         Log.d(TAG, "pressBack()");
@@ -254,12 +265,25 @@
     }
 
     /**
-     * Presses the home button.
+     * Presses the Home button.
      */
     void pressHome() {
         Log.d(TAG, "pressHome()");
         mDevice.pressHome();
     }
+
+    /**
+     * Uses the Recents button to switch back to previous activity
+     */
+    void switchAppsUsingRecents() throws RemoteException {
+        Log.d(TAG, "switchAppsUsingRecents()");
+
+        // Press once to show list of apps...
+        mDevice.pressRecentApps();
+        // ...press again to go back to the activity.
+        mDevice.pressRecentApps();
+    }
+
     /**
      * Asserts the save snackbar is not showing and returns it.
      */
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WelcomeActivity.java b/tests/autofillservice/src/android/autofillservice/cts/WelcomeActivity.java
index 637966d..bda2d82 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/WelcomeActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/WelcomeActivity.java
@@ -15,8 +15,12 @@
  */
 package android.autofillservice.cts;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.test.uiautomator.UiObject2;
 import android.text.TextUtils;
 import android.util.Log;
 import android.widget.TextView;
@@ -62,4 +66,19 @@
             sInstance.finish();
         }
     }
+
+    // TODO: reuse in other places
+    static void assertShowingDefaultMessage(UiBot uiBot) throws Exception {
+        assertShowing(uiBot, null);
+    }
+
+    // TODO: reuse in other places
+    static void assertShowing(UiBot uiBot, @Nullable String expectedMessage) throws Exception {
+        final UiObject2 activity = uiBot.assertShownByRelativeId("output");
+        if (expectedMessage == null) {
+            expectedMessage = "Welcome to the jungle!";
+        }
+        assertWithMessage("wrong text on '%s'", activity).that(activity.getText())
+                .isEqualTo(expectedMessage);
+    }
 }
diff --git a/tests/pdf/AndroidTest.xml b/tests/pdf/AndroidTest.xml
index 5a0f718..ab88726 100644
--- a/tests/pdf/AndroidTest.xml
+++ b/tests/pdf/AndroidTest.xml
@@ -14,11 +14,14 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Pdf test cases">
+    <option name="not-shardable" value="true" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
+
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsPdfTestCases.apk" />
     </target_preparer>
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.graphics.pdf.cts" />
         <option name="runtime-hint" value="5m" />
diff --git a/tests/tests/database/Android.mk b/tests/tests/database/Android.mk
index 1ebbe2d..0e24c15 100644
--- a/tests/tests/database/Android.mk
+++ b/tests/tests/database/Android.mk
@@ -25,6 +25,7 @@
     android-common \
     ctstestrunner \
     ctstestrunner \
+    ub-uiautomator \
     junit \
     legacy-android-test
 
@@ -37,4 +38,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
+# Enforce public / test api only
+LOCAL_SDK_VERSION := test_current
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/database/src/android/database/sqlite/cts/DatabaseTestUtils.java b/tests/tests/database/src/android/database/sqlite/cts/DatabaseTestUtils.java
new file mode 100644
index 0000000..5b52790
--- /dev/null
+++ b/tests/tests/database/src/android/database/sqlite/cts/DatabaseTestUtils.java
@@ -0,0 +1,53 @@
+/*
+ * 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.database.sqlite.cts;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+/**
+ * Common utility methods for testing
+ */
+class DatabaseTestUtils {
+
+    private static final String TAG = "SQLiteOpenHelperTest";
+
+    static boolean waitForConnectionToClose(int maxAttempts, int pollIntervalMs)
+            throws Exception {
+        for (int i = 0; i < maxAttempts; i++) {
+            String output = getDbInfoOutput();
+            Log.d(TAG, "waitForConnectionToClose #" + i + ": " + output);
+            if (!output.contains("Connection #0:")) {
+                return true;
+            }
+            Thread.sleep(pollIntervalMs);
+        }
+        return false;
+    }
+
+    static String getDbInfoOutput() throws Exception {
+        Context ctx = InstrumentationRegistry.getInstrumentation().getContext();
+        return executeShellCommand("dumpsys dbinfo " + ctx.getPackageName());
+    }
+
+    static String executeShellCommand(String cmd) throws Exception {
+        return UiDevice.getInstance(
+                InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+    }
+}
diff --git a/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java b/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java
index 91e4c4b..26f8794 100644
--- a/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java
+++ b/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java
@@ -36,11 +36,16 @@
 import android.database.sqlite.SQLiteQuery;
 import android.database.sqlite.SQLiteStatement;
 import android.database.sqlite.SQLiteTransactionListener;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import static android.database.sqlite.cts.DatabaseTestUtils.getDbInfoOutput;
+import static android.database.sqlite.cts.DatabaseTestUtils.waitForConnectionToClose;
+
 public class SQLiteDatabaseTest extends AndroidTestCase {
     private static final String TAG = "SQLiteDatabaseTest";
     private SQLiteDatabase mDatabase;
@@ -1539,4 +1544,44 @@
         }
         assertTrue("No dbstat found for " + mDatabaseFile.getName(), dbStatFound);
     }
+
+    public void testCloseIdleConnection() throws Exception {
+        mDatabase.close();
+        SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+                .setIdleConnectionTimeout(1000).build();
+        mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile, params);
+        // Wait a bit and check that connection is still open
+        Thread.sleep(600);
+        String output = getDbInfoOutput();
+        assertTrue("Connection #0 should be open. Output: " + output,
+                output.contains("Connection #0:"));
+
+        // Now cause idle timeout and check that connection is closed
+        // We wait up to 5 seconds, which is longer than required 1 s to accommodate for delays in
+        // message processing when system is busy
+        boolean connectionWasClosed = waitForConnectionToClose(10, 500);
+        assertTrue("Connection #0 should be closed", connectionWasClosed);
+    }
+
+    public void testNoCloseIdleConnectionForAttachDb() throws Exception {
+        mDatabase.close();
+        SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+                .setIdleConnectionTimeout(50).build();
+        mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile, params);
+        // Attach db and verify size of the list of attached databases (includes main db)
+        assertEquals(1, mDatabase.getAttachedDbs().size());
+        mDatabase.execSQL("ATTACH DATABASE ':memory:' as memdb");
+        assertEquals(2, mDatabase.getAttachedDbs().size());
+        // Wait longer (500ms) to catch cases when timeout processing was delayed
+        boolean connectionWasClosed = waitForConnectionToClose(5, 100);
+        assertFalse("Connection #0 should be open", connectionWasClosed);
+    }
+
+    public void testSetIdleConnectionTimeoutValidation() throws Exception {
+        try {
+            new SQLiteDatabase.OpenParams.Builder().setIdleConnectionTimeout(-1).build();
+            fail("Negative timeout should be rejected");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
 }
diff --git a/tests/tests/database/src/android/database/sqlite/cts/SQLiteOpenHelperTest.java b/tests/tests/database/src/android/database/sqlite/cts/SQLiteOpenHelperTest.java
index 2d64cf3..e28bef9 100644
--- a/tests/tests/database/src/android/database/sqlite/cts/SQLiteOpenHelperTest.java
+++ b/tests/tests/database/src/android/database/sqlite/cts/SQLiteOpenHelperTest.java
@@ -25,9 +25,14 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQuery;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import static android.database.sqlite.cts.DatabaseTestUtils.getDbInfoOutput;
+import static android.database.sqlite.cts.DatabaseTestUtils.waitForConnectionToClose;
+
 /**
  * Test {@link SQLiteOpenHelper}.
  */
@@ -161,6 +166,30 @@
         assertTrue("No dbstat found for " + dbName, dbStatFound);
     }
 
+    public void testCloseIdleConnection() throws Exception {
+        mOpenHelper.setIdleConnectionTimeout(1000);
+        mOpenHelper.getReadableDatabase();
+        // Wait a bit and check that connection is still open
+        Thread.sleep(600);
+        String output = getDbInfoOutput();
+        assertTrue("Connection #0 should be open. Output: " + output,
+                output.contains("Connection #0:"));
+
+        // Now cause idle timeout and check that connection is closed
+        // We wait up to 5 seconds, which is longer than required 1 s to accommodate for delays in
+        // message processing when system is busy
+        boolean connectionWasClosed = waitForConnectionToClose(10, 500);
+        assertTrue("Connection #0 should be closed", connectionWasClosed);
+    }
+
+    public void testSetIdleConnectionTimeoutValidation() throws Exception {
+        try {
+            mOpenHelper.setIdleConnectionTimeout(-1);
+            fail("Negative timeout should be rejected");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
     private MockOpenHelper getOpenHelper() {
         return new MockOpenHelper(mContext, TEST_DATABASE_NAME, mFactory, TEST_VERSION);
     }
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
index 010d992..72838e5 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
@@ -264,13 +264,10 @@
             public int getHeight() {
                 return super.getHeight() + OFFSET;
             }
+
             @Override
-            public int getMaxHeight() {
-                return super.getHeight() * 2 + OFFSET;
-            }
-            @Override
-            public int getMaxWidth() {
-                return super.getWidth() * 2 + OFFSET;
+            public boolean isAbrEnabled() {
+                return true;
             }
         };
     }
@@ -281,13 +278,10 @@
             public int getWidth() {
                 return super.getWidth() + OFFSET;
             }
+
             @Override
-            public int getMaxHeight() {
-                return super.getHeight() * 2 + OFFSET;
-            }
-            @Override
-            public int getMaxWidth() {
-                return super.getWidth() * 2 + OFFSET;
+            public boolean isAbrEnabled() {
+                return true;
             }
         };
     }
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
index 0e92e3d..58f1607 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertNotNull;
 
 import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.MediaUtils;
 
 import android.annotation.TargetApi;
 import android.annotation.SuppressLint;
@@ -38,6 +39,7 @@
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
 import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo.VideoCapabilities;
 import android.media.MediaCodecList;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
@@ -480,10 +482,27 @@
             if (ApiLevelUtil.isBefore(Build.VERSION_CODES.KITKAT)) {
                 return;
             }
-            if (videoFormat.getMaxWidth() != VideoFormat.INT_UNSET
-                && videoFormat.getMaxHeight() != VideoFormat.INT_UNSET) {
-                mediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, videoFormat.getMaxWidth());
-                mediaFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, videoFormat.getMaxHeight());
+            // Set KEY_MAX_WIDTH and KEY_MAX_HEIGHT when isAbrEnabled() is set.
+            if (videoFormat.isAbrEnabled()) {
+                try {
+                    // Check for max resolution supported by the codec.
+                    final MediaCodec decoder = MediaUtils.getDecoder(mediaFormat);
+                    final VideoCapabilities videoCapabilities = MediaUtils.getVideoCapabilities(
+                            decoder.getName(), videoFormat.getMimeType());
+                    decoder.release();
+                    final int maxWidth = videoCapabilities.getSupportedWidths().getUpper();
+                    final int maxHeight =
+                            videoCapabilities.getSupportedHeightsFor(maxWidth).getUpper();
+                    if (maxWidth >= videoFormat.getWidth() && maxHeight >= videoFormat.getHeight()) {
+                        mediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, maxWidth);
+                        mediaFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, maxHeight);
+                        return;
+                    }
+                } catch (NullPointerException exception) { /* */ }
+                // Set max width/height to current size if can't get codec's max supported
+                // width/height or max is not greater than the current size.
+                mediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, videoFormat.getWidth());
+                mediaFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, videoFormat.getHeight());
             }
         }
 
@@ -1591,6 +1610,10 @@
         return getParsedName().getHeight();
     }
 
+    public boolean isAbrEnabled() {
+        return false;
+    }
+
     public String getOriginalSize() {
         if (width == INT_UNSET || height == INT_UNSET) {
             return getParsedName().getSize();
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index aaf3310..35d2cd8 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -1613,10 +1613,10 @@
 
         // Run twice to check if repeated selection-deselection on the same track works well.
         for (int i = 0; i < 2; i++) {
-            // Waits until at least one subtitle is fired. Timeout is 2 seconds.
+            // Waits until at least one subtitle is fired. Timeout is 2.5 seconds.
             selectSubtitleTrack(i);
             mOnSubtitleDataCalled.reset();
-            assertTrue(mOnSubtitleDataCalled.waitForSignal(2000));
+            assertTrue(mOnSubtitleDataCalled.waitForSignal(2500));
 
             // Try deselecting track.
             deselectSubtitleTrack(i);
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 7997a7d..6af40a8 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -94,6 +94,7 @@
     <protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
 
+    <!-- @deprecated This is rarely used and will be phased out soon. -->
     <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
 
     <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
@@ -146,6 +147,7 @@
     <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" />
     <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
     <protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
+    <protected-broadcast android:name="android.bluetooth.device.action.BATTERY_LEVEL_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
     <protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
     <protected-broadcast
@@ -277,6 +279,7 @@
     <protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" />
     <protected-broadcast android:name="com.android.nfc.handover.action.ALLOW_CONNECT" />
     <protected-broadcast android:name="com.android.nfc.handover.action.DENY_CONNECT" />
+    <protected-broadcast android:name="com.android.nfc.handover.action.TIMEOUT_CONNECT" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
@@ -302,6 +305,7 @@
     <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
+    <protected-broadcast android:name="com.android.internal.action.EUICC_FACTORY_RESET" />
     <protected-broadcast android:name="com.android.server.usb.ACTION_OPEN_IN_APPS" />
     <protected-broadcast android:name="com.android.server.am.DELETE_DUMPHEAP" />
     <protected-broadcast android:name="com.android.server.net.action.SNOOZE_WARNING" />
@@ -454,6 +458,7 @@
     <protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" />
     <protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
     <protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
+    <protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
 
     <protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
     <protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
@@ -540,6 +545,7 @@
     <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
     <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
     <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
+    <protected-broadcast android:name="com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
@@ -764,7 +770,7 @@
         android:permissionGroup="android.permission-group.LOCATION"
         android:label="@string/permlab_accessFineLocation"
         android:description="@string/permdesc_accessFineLocation"
-        android:protectionLevel="dangerous|ephemeral" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- Allows an app to access approximate location.
          Alternatively, you might want {@link #ACCESS_FINE_LOCATION}.
@@ -774,7 +780,7 @@
         android:permissionGroup="android.permission-group.LOCATION"
         android:label="@string/permlab_accessCoarseLocation"
         android:description="@string/permdesc_accessCoarseLocation"
-        android:protectionLevel="dangerous|ephemeral" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device telephony                         -->
@@ -808,13 +814,13 @@
         android:protectionLevel="dangerous" />
 
     <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
-         granted by {@link #READ_PHONE_STATE} but is exposed to ephemeral applications.
+         granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
          <p>Protection level: dangerous-->
     <permission android:name="android.permission.READ_PHONE_NUMBERS"
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_readPhoneNumbers"
         android:description="@string/permdesc_readPhoneNumbers"
-        android:protectionLevel="dangerous|ephemeral" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- Allows an application to initiate a phone call without going through
         the Dialer user interface for the user to confirm the call.
@@ -953,18 +959,18 @@
     <!-- ====================================================================== -->
 
     <!-- @hide Allows an application to Access UCE-Presence.
-         <p>Protection level: dangerous
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
         android:permissionGroup="android.permission-group.PHONE"
-        android:protectionLevel="signatureOrSystem"/>
+        android:protectionLevel="signature|privileged"/>
 
     <!-- @hide Allows an application to Access UCE-OPTIONS.
-         <p>Protection level: dangerous
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
         android:permissionGroup="android.permission-group.PHONE"
-        android:protectionLevel="signatureOrSystem"/>
+        android:protectionLevel="signature|privileged"/>
 
 
 
@@ -994,7 +1000,7 @@
         android:permissionGroup="android.permission-group.CAMERA"
         android:label="@string/permlab_camera"
         android:description="@string/permdesc_camera"
-        android:protectionLevel="dangerous|ephemeral" />
+        android:protectionLevel="dangerous|instant" />
 
 
     <!-- ====================================================================== -->
@@ -1236,7 +1242,7 @@
     <permission android:name="android.permission.INTERNET"
         android:description="@string/permdesc_createNetworkSockets"
         android:label="@string/permlab_createNetworkSockets"
-        android:protectionLevel="normal|ephemeral" />
+        android:protectionLevel="normal|instant" />
 
     <!-- Allows applications to access information about networks.
          <p>Protection level: normal
@@ -1244,7 +1250,7 @@
     <permission android:name="android.permission.ACCESS_NETWORK_STATE"
         android:description="@string/permdesc_accessNetworkState"
         android:label="@string/permlab_accessNetworkState"
-        android:protectionLevel="normal|ephemeral" />
+        android:protectionLevel="normal|instant" />
 
     <!-- Allows applications to access information about Wi-Fi networks.
          <p>Protection level: normal
@@ -1467,7 +1473,7 @@
     <permission android:name="android.permission.VIBRATE"
         android:label="@string/permlab_vibrate"
         android:description="@string/permdesc_vibrate"
-        android:protectionLevel="normal|ephemeral" />
+        android:protectionLevel="normal|instant" />
 
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
          from dimming.
@@ -1476,7 +1482,7 @@
     <permission android:name="android.permission.WAKE_LOCK"
         android:label="@string/permlab_wakeLock"
         android:description="@string/permdesc_wakeLock"
-        android:protectionLevel="normal|ephemeral" />
+        android:protectionLevel="normal|instant" />
 
     <!-- Allows using the device's IR transmitter, if available.
          <p>Protection level: normal
@@ -1522,7 +1528,7 @@
     <permission android:name="android.permission.HARDWARE_TEST"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi Allows access to FM
+    <!-- @SystemApi Allows access to Broadcast Radio
          @hide This is not a third-party API (intended for system apps).-->
     <permission android:name="android.permission.ACCESS_BROADCAST_RADIO"
         android:protectionLevel="signature|privileged" />
@@ -1694,7 +1700,8 @@
     <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to send EMBMS download intents to apps-->
+      <!-- Allows an application to send EMBMS download intents to apps
+           @hide -->
     <permission android:name="android.permission.SEND_EMBMS_INTENTS"
         android:protectionLevel="signature|privileged" />
 
@@ -1938,6 +1945,11 @@
         android:description="@string/permdesc_useDataInBackground"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to set display offsets for the screen.
+         This permission is not available to third party applications. -->
+    <permission android:name="android.permission.SET_DISPLAY_OFFSET"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows a companion app to run in the background.
          <p>Protection level: normal
     -->
@@ -1955,12 +1967,6 @@
                 android:protectionLevel="normal" />
 
 
-    <!-- @hide Allows an application to set display offsets for the screen.
-         This permission is not available to third party applications. -->
-    <permission android:name="android.permission.SET_DISPLAY_OFFSET"
-                android:protectionLevel="signature|privileged" />
-    <uses-permission android:name="android.permission.SET_DISPLAY_OFFSET"/>
-
     <!-- ================================== -->
     <!-- Permissions affecting the system wallpaper -->
     <!-- ================================== -->
@@ -2218,7 +2224,7 @@
 
     <!-- Allows an application to clear the caches of all installed
          applications on the device.
-         <p>Protection level: system|signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.CLEAR_APP_CACHE"
         android:protectionLevel="signature|privileged" />
@@ -2261,13 +2267,13 @@
          it off to the installer components.
          @hide -->
     <permission android:name="android.permission.UPDATE_TIME_ZONE_RULES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a time zone rule updater application,
          to ensure that only the system can trigger it.
          @hide -->
     <permission android:name="android.permission.TRIGGER_TIME_ZONE_RULES_CHECK"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
     <uses-permission android:name="android.permission.TRIGGER_TIME_ZONE_RULES_CHECK"/>
 
     <!-- Allows the system to reset throttling in shortcut manager.
@@ -2410,7 +2416,7 @@
          @hide
     -->
     <permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"
-        android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer" />
 
     <!-- @SystemApi Allows an application to manage (create, destroy,
          Z-order) application tokens in the window manager.
@@ -2540,10 +2546,9 @@
             android:protectionLevel="signature" />
 
     <!-- Allows applications to get the installed and enabled print services.
-     @hide
-     @SystemApi
-     @TestApi
-     <p>Protection level: signature|preinstalled
+         @hide
+         @SystemApi
+         <p>Protection level: signature|preinstalled
     -->
     <permission android:name="android.permission.READ_PRINT_SERVICES"
         android:protectionLevel="signature|preinstalled" />
@@ -2596,7 +2601,7 @@
 
     <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
          to ensure that only the system can bind to it.
-         <p>Protection level: system|signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_WALLPAPER"
         android:protectionLevel="signature|privileged" />
@@ -2633,7 +2638,7 @@
 
     <!-- Must be required by a {@link android.media.tv.TvInputService}
          to ensure that only the system can bind to it.
-         <p>Protection level: signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_TV_INPUT"
         android:protectionLevel="signature|privileged" />
@@ -2843,9 +2848,9 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to disable/enable input devices.
-     Could be used to prevent unwanted touch events
-     on a touchscreen, for example during swimming or rain.
-     @hide -->
+         Could be used to prevent unwanted touch events
+         on a touchscreen, for example during swimming or rain.
+         @hide -->
     <permission android:name="android.permission.DISABLE_INPUT_DEVICE"
         android:protectionLevel="signature" />
 
@@ -3161,9 +3166,7 @@
     <permission android:name="android.permission.MANAGE_NETWORK_POLICY"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi Allows an application to account its network traffic against other UIDs. Used
-         by system services like download manager and media server. Not for use by
-         third party apps. @hide -->
+    <!-- @SystemApi @hide @deprecated use UPDATE_DEVICE_STATS instead -->
     <permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
         android:protectionLevel="signature|privileged" />
 
@@ -3245,7 +3248,7 @@
                 android:protectionLevel="signature" />
 
     <!-- Allows notifications to be colorized
-     <p>Not for use by third-party applications. @hide -->
+         <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
                 android:protectionLevel="signature|setup" />
 
@@ -3399,7 +3402,7 @@
     <!-- The system process that is allowed to bind to services in carrier apps will
          have this permission. Carrier apps should use this permission to protect
          their services that only the system is allowed to bind to.
-         <p>Protection level: system|signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_CARRIER_SERVICES"
         android:label="@string/permlab_bindCarrierServices"
@@ -3533,7 +3536,7 @@
 
     <!-- Allows an instant app to create foreground services. -->
     <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
-        android:protectionLevel="signature|development|ephemeral|appop" />
+        android:protectionLevel="signature|development|instant|appop" />
 
     <application android:process="system"
                  android:persistent="true"
@@ -3869,6 +3872,11 @@
         <service android:name="com.android.server.PreloadsFileCacheExpirationJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
+
+        <service android:name="com.android.server.camera.CameraStatsJobService"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
     </application>
 
 </manifest>
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 0189408..3206af7 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -151,8 +151,8 @@
         // OEMs cannot define new ephemeral permissions
         for (String permission : declaredPermissionsMap.keySet()) {
             PermissionInfo info = declaredPermissionsMap.get(permission);
-            if ((info.protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) == 0) {
-                offendingList.add("Cannot define new ephemeral permission " + permission);
+            if ((info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0) {
+                offendingList.add("Cannot define new instant permission " + permission);
             }
         }
 
@@ -240,8 +240,8 @@
                 case "setup": {
                     protectionLevel |= PermissionInfo.PROTECTION_FLAG_SETUP;
                 } break;
-                case "ephemeral": {
-                    protectionLevel |= PermissionInfo.PROTECTION_FLAG_EPHEMERAL;
+                case "instant": {
+                    protectionLevel |= PermissionInfo.PROTECTION_FLAG_INSTANT;
                 } break;
                 case "runtime": {
                     protectionLevel |= PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY;
diff --git a/tests/tests/print/AndroidTest.xml b/tests/tests/print/AndroidTest.xml
index 1573840..1c771d6 100644
--- a/tests/tests/print/AndroidTest.xml
+++ b/tests/tests/print/AndroidTest.xml
@@ -14,11 +14,14 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Print test cases">
+    <option name="not-shardable" value="true" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
+
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsPrintTestCases.apk" />
     </target_preparer>
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.print.cts" />
         <option name="runtime-hint" value="33m00s" />
diff --git a/tests/tests/security/src/android/security/cts/EffectBundleTest.java b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
index 32c3b5c..289f362 100644
--- a/tests/tests/security/src/android/security/cts/EffectBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
@@ -17,6 +17,7 @@
 package android.security.cts;
 
 import android.media.audiofx.AudioEffect;
+import android.media.audiofx.EnvironmentalReverb;
 import android.media.audiofx.Equalizer;
 import android.media.MediaPlayer;
 import android.platform.test.annotations.SecurityTest;
@@ -27,6 +28,7 @@
 import java.nio.ByteOrder;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.UUID;
 
 @SecurityTest
 public class EffectBundleTest extends InstrumentationTestCase {
@@ -39,6 +41,11 @@
     private static final int MEDIA_SHORT = 0;
     private static final int MEDIA_LONG = 1;
 
+    // should match audio_effect.h (native)
+    private static final int EFFECT_CMD_SET_PARAM = 5;
+
+    private static final int intSize = 4;
+
     //Testing security bug: 32436341
     public void testEqualizer_getParamCenterFreq() throws Exception {
         testGetParam(MEDIA_SHORT, Equalizer.PARAM_CENTER_FREQ, INVALID_BAND_ARRAY, mValue0,
@@ -162,6 +169,42 @@
                 eqSetParamProperties(MEDIA_LONG));
     }
 
+    //Testing security bug: 63662938
+    @SecurityTest
+    public void testDownmix_setParameter() throws Exception {
+        verifyZeroPVSizeRejectedForSetParameter(
+                EFFECT_TYPE_DOWNMIX, new int[] { DOWNMIX_PARAM_TYPE });
+    }
+
+    /**
+     * Definitions for the downmix effect. Taken from
+     * system/media/audio/include/system/audio_effects/effect_downmix.h
+     * This effect is normally not exposed to applications.
+     */
+    private static final UUID EFFECT_TYPE_DOWNMIX = UUID
+            .fromString("381e49cc-a858-4aa2-87f6-e8388e7601b2");
+    private static final int DOWNMIX_PARAM_TYPE = 0;
+
+    //Testing security bug: 63526567
+    @SecurityTest
+    public void testEnvironmentalReverb_setParameter() throws Exception {
+        verifyZeroPVSizeRejectedForSetParameter(
+                AudioEffect.EFFECT_TYPE_ENV_REVERB, new int[] {
+                  EnvironmentalReverb.PARAM_ROOM_LEVEL,
+                  EnvironmentalReverb.PARAM_ROOM_HF_LEVEL,
+                  EnvironmentalReverb.PARAM_DECAY_TIME,
+                  EnvironmentalReverb.PARAM_DECAY_HF_RATIO,
+                  EnvironmentalReverb.PARAM_REFLECTIONS_LEVEL,
+                  EnvironmentalReverb.PARAM_REFLECTIONS_DELAY,
+                  EnvironmentalReverb.PARAM_REVERB_LEVEL,
+                  EnvironmentalReverb.PARAM_REVERB_DELAY,
+                  EnvironmentalReverb.PARAM_DIFFUSION,
+                  EnvironmentalReverb.PARAM_DENSITY,
+                  10 // EnvironmentalReverb.PARAM_PROPERTIES
+                }
+        );
+    }
+
     private boolean eqSetParamProperties(int media) {
         MediaPlayer mp = null;
         Equalizer eq = null;
@@ -170,10 +213,9 @@
             mp = MediaPlayer.create(getInstrumentation().getContext(),  getMediaId(media));
             eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
 
-            int intSize = 4; //bytes
             int shortSize = 2; //bytes
 
-            int cmdCode = 5; // EFFECT_CMD_SET_PARAM
+            int cmdCode = EFFECT_CMD_SET_PARAM;
             byte command[] = concatArrays(/*status*/ intToByteArray(0),
                     /*psize*/ intToByteArray(1 * intSize),
                     /*vsize*/ intToByteArray(2 * shortSize),
@@ -214,7 +256,6 @@
             eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
 
             short band = 2;
-            int intSize = 4; //bytes
 
             //baseline
             int cmdCode = 8; // EFFECT_CMD_GET_PARAM
@@ -364,6 +405,74 @@
         }
     }
 
+    // Verifies that for all the effects of the specified type
+    // an attempt to pass psize = 0 or vsize = 0 to 'set parameter' command
+    // is rejected by the effect.
+    private void verifyZeroPVSizeRejectedForSetParameter(
+            UUID effectType, final int paramCodes[]) throws Exception {
+
+        boolean effectFound = false;
+        for (AudioEffect.Descriptor descriptor : AudioEffect.queryEffects()) {
+            if (descriptor.type.compareTo(effectType) != 0) continue;
+
+            effectFound = true;
+            AudioEffect ae = null;
+            MediaPlayer mp = null;
+            try {
+                mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good);
+                java.lang.reflect.Constructor ct = AudioEffect.class.getConstructor(
+                        UUID.class, UUID.class, int.class, int.class);
+                try {
+                    ae = (AudioEffect) ct.newInstance(descriptor.type, descriptor.uuid,
+                            /*priority*/ 0, mp.getAudioSessionId());
+                } catch (Exception e) {
+                    // Not every effect can be instantiated by apps.
+                    Log.w(TAG, "Failed to create effect " + descriptor.uuid);
+                    continue;
+                }
+                java.lang.reflect.Method command = AudioEffect.class.getDeclaredMethod(
+                        "command", int.class, byte[].class, byte[].class);
+                for (int paramCode : paramCodes) {
+                    executeSetParameter(ae, command, intSize, 0, paramCode);
+                    executeSetParameter(ae, command, 0, intSize, paramCode);
+                }
+            } finally {
+                if (ae != null) {
+                    ae.release();
+                }
+                if (mp != null) {
+                    mp.release();
+                }
+            }
+        }
+
+        if (!effectFound) {
+            Log.w(TAG, "No effect with type " + effectType + " was found");
+        }
+    }
+
+    private void executeSetParameter(AudioEffect ae, java.lang.reflect.Method command,
+            int paramSize, int valueSize, int paramCode) throws Exception {
+        byte cmdBuf[] = concatArrays(/*status*/ intToByteArray(0),
+                /*psize*/ intToByteArray(paramSize),
+                /*vsize*/ intToByteArray(valueSize),
+                /*data[0]*/ intToByteArray(paramCode));
+        byte reply[] = new byte[intSize];
+        Integer ret = (Integer)command.invoke(ae, EFFECT_CMD_SET_PARAM, cmdBuf, reply);
+        if (ret >= 0) {
+            int val = byteArrayToInt(reply, 0 /*offset*/);
+            assertTrue("Negative reply value expected, effect " + ae.getDescriptor().uuid +
+                    ", parameter " + paramCode + ", reply value " + val,
+                    val < 0);
+        } else {
+            // Some effect implementations detect this condition at the command dispatch level,
+            // and reject command execution. That's also OK, but log a message so the test
+            // author can double check if 'paramCode' is correct.
+            Log.w(TAG, "\"Set parameter\" command rejected for effect " + ae.getDescriptor().uuid +
+                    ", parameter " + paramCode + ", return code " + ret);
+        }
+    }
+
     private static byte[] intToByteArray(int value) {
         ByteBuffer converter = ByteBuffer.allocate(4);
         converter.order(ByteOrder.nativeOrder());
diff --git a/tests/tests/telecom/src/android/telecom/cts/RttOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/RttOperationsTest.java
index a11079f..e97a9ac 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RttOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RttOperationsTest.java
@@ -43,6 +43,10 @@
     }
 
     public void testOutgoingRttCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeRttCall(false);
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -52,6 +56,10 @@
     }
 
     public void testIncomingRttCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeRttCall(true);
         final MockConnection connection = verifyConnectionForIncomingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -61,6 +69,10 @@
     }
 
     public void testLocalRttUpgradeAccepted() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -79,6 +91,10 @@
     }
 
     public void testLocalRttUpgradeRejected() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -99,6 +115,10 @@
     }
 
     public void testAcceptRemoteRttUpgrade() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -118,6 +138,10 @@
     }
 
     public void testRejectRemoteRttRequest() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -138,6 +162,10 @@
     }
 
     public void testLocalRttTermination() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeRttCall(false);
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -153,6 +181,10 @@
     }
 
     public void testRemoteRttTermination() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeRttCall(false);
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
diff --git a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
index dcdd4f2..21fdd89 100644
--- a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
+++ b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
@@ -356,6 +356,8 @@
 
         LinearLayout mid = new LinearLayout(activity);
         Button but = new Button(activity);
+        but.setRight(but.getLeft() + 10);
+        but.setBottom(but.getTop() + 10);
         but.setFocusableInTouchMode(true);
         but.setVisibility(View.INVISIBLE);
         mid.addView(but, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
index eb59329..cd463a3 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -40,6 +40,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.PointerIcon;
 import android.view.View;
 import android.view.cts.R;
 import android.widget.FrameLayout;
@@ -89,6 +90,9 @@
 
         getWindow().getDecorView().setSystemUiVisibility(
                 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
+        // Set the NULL pointer icon so that it won't obstruct the captured image.
+        getWindow().getDecorView().setPointerIcon(
+                PointerIcon.getSystemIcon(this, PointerIcon.TYPE_NULL));
 
         mProjectionManager =
                 (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index b1ddfcb..a21e4cc 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -58,10 +59,12 @@
 import android.webkit.CookieSyncManager;
 import android.webkit.DownloadListener;
 import android.webkit.JavascriptInterface;
+import android.webkit.SafeBrowsingResponse;
 import android.webkit.ValueCallback;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebChromeClient;
 import android.webkit.WebIconDatabase;
+import android.webkit.WebResourceRequest;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebView.HitTestResult;
@@ -97,7 +100,9 @@
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.http.Header;
@@ -2613,6 +2618,54 @@
         assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
+    public void testSetSafeBrowsingWhitelistWithMalformedList() throws Exception {
+        List whitelist = new ArrayList<String>();
+        // Protocols are not supported in the whitelist
+        whitelist.add("http://google.com");
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebView.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
+            @Override
+            public void onReceiveValue(Boolean success) {
+                assertFalse(success);
+                resultLatch.countDown();
+            }
+        });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    public void testSetSafeBrowsingWhitelistWithValidList() throws Exception {
+        List whitelist = new ArrayList<String>();
+        whitelist.add("safe-browsing");
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebView.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
+            @Override
+            public void onReceiveValue(Boolean success) {
+                assertTrue(success);
+                resultLatch.countDown();
+            }
+        });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+
+        final CountDownLatch resultLatch2 = new CountDownLatch(1);
+        mOnUiThread.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                resultLatch2.countDown();
+            }
+
+            @Override
+            public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType,
+                    SafeBrowsingResponse callback) {
+                Assert.fail("Should not invoke onSafeBrowsingHit");
+            }
+        });
+
+        mOnUiThread.loadUrl("chrome://safe-browsing/match?type=malware");
+
+        // Wait until page load has completed
+        assertTrue(resultLatch2.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
     @UiThreadTest
     public void testGetWebViewClient() throws Exception {
         if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -2682,6 +2735,71 @@
         assertSame(webView.getTextClassifier(), classifier);
     }
 
+    private static class MockContext extends ContextWrapper {
+        private boolean mGetApplicationContextWasCalled;
+
+        public MockContext(Context context) {
+            super(context);
+        }
+
+        public Context getApplicationContext() {
+            mGetApplicationContextWasCalled = true;
+            return super.getApplicationContext();
+        }
+
+        public boolean wasGetApplicationContextCalled() {
+            return mGetApplicationContextWasCalled;
+        }
+    }
+
+    public void testInitSafeBrowsingUseApplicationContext() throws Exception {
+        final MockContext ctx = new MockContext(getActivity());
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebView.initSafeBrowsing(ctx, new ValueCallback<Boolean>() {
+            @Override
+            public void onReceiveValue(Boolean value) {
+                assertTrue(ctx.wasGetApplicationContextCalled());
+                resultLatch.countDown();
+                return;
+            }
+        });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    public void testInitSafeBrowsingWithNullCallbackDoesntCrash() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        WebView.initSafeBrowsing(getActivity().getApplicationContext(), null);
+    }
+
+    public void testInitSafeBrowsingInvokesCallback() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebView.initSafeBrowsing(getActivity().getApplicationContext(),
+                new ValueCallback<Boolean>() {
+            @Override
+            public void onReceiveValue(Boolean value) {
+                assertTrue(Looper.getMainLooper().isCurrentThread());
+                resultLatch.countDown();
+                return;
+            }
+        });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    public void testShutdownSafeBrowsingDoesntCrash() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        WebView.shutdownSafeBrowsing();
+    }
+
     private void savePrintedPage(final PrintDocumentAdapter adapter,
             final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
         adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index dfc20e6..262d629 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -121,9 +121,6 @@
     <!-- b/36686383 -->
     <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testANR" />
 
-    <!-- b/37545399 -->
-    <option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.LightBarTests#testLightNavigationBar" />
-
     <!-- b/37482372 -->
     <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowHistoryPreservePortraitTest" />
     <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowInOutPortraitTest" />
diff --git a/tools/cts-tradefed/res/config/cts-reference-aosp.xml b/tools/cts-tradefed/res/config/cts-reference-aosp.xml
index 19e4f69..7fbf4cb 100644
--- a/tools/cts-tradefed/res/config/cts-reference-aosp.xml
+++ b/tools/cts-tradefed/res/config/cts-reference-aosp.xml
@@ -96,4 +96,42 @@
     -->
     <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testEcAttestation" />
     <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testRsaAttestation" />
+
+    <!-- Exclude test cases for b/64488375
+    -->
+
+    <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testVoiceCommand" />
+    <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testVoiceSearchHandsFree" />
+
+    <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_metered" />
+
+    <option name="compatibility:exclude-filter" value="CtsNetTestCasesLegacyApi22 android.net.cts.legacy.api22.ConnectivityManagerLegacyTest#testStartUsingNetworkFeature_enableHipri" />
+
+    <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.NoSystemFunctionPermissionTest#testSendSms" />
+
+    <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.NoReceiveSmsPermissionTest#testAppSpecificSmsToken" />
+    <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.NoReceiveSmsPermissionTest#testReceiveTextMessage" />
+    <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.PrivappPermissionsTest#testPrivappPermissionsEnforcement" />
+
+    <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForBinderInVendorBan" />
+    <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForSocketsBetweenCoreAndVendorBan" />
+    <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForVendorExecutingCore" />
+
+    <option name="compatibility:exclude-filter" value="CtsContentTestCases android.signature.cts.IntentTest#shouldNotFindUnexpectedIntents" />
+
+    <option name="compatibility:exclude-filter" value="CtsTextTestCases android.text.cts.EmojiTest#testEmojiGlyph" />
+    <option name="compatibility:exclude-filter" value="CtsTextTestCases android.text.util.cts.LinkifyTest#testAddLinks_doesNotAddLinksForUrlWithoutProtocolAndWithoutKnownTld" />
+
+    <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.PathClippingTests#testWebViewClipWithCircle" />
+
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewClientTest#testOnUnhandledKeyEvent" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testFindAll" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testFindNext" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testFlingScroll" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testGetContentHeight" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testGetHitTestResult" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testPageScroll" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testRequestFocusNodeHref" />
+    <option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testRequestImageRef" />
+
 </configuration>