Merge "CTS for ForegroundServiceAccessAppOpOccurred atom" into rvc-dev
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
index e5300ab..2a322aa 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
@@ -5,4 +5,5 @@
     <string name="Ask">Ask every time</string>
     <string name="Allow">Allow</string>
     <string name="AllowAll">Allow all the time</string>
+    <string name="AllowForeground">Allow only while using the app</string>
 </resources>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
index e5300ab..2a322aa 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
@@ -5,4 +5,5 @@
     <string name="Ask">Ask every time</string>
     <string name="Allow">Allow</string>
     <string name="AllowAll">Allow all the time</string>
+    <string name="AllowForeground">Allow only while using the app</string>
 </resources>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index 8b5630c..da6e44b 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -16,18 +16,16 @@
 
 package com.android.cts.usepermission;
 
-import static com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject;
 import static com.android.compatibility.common.util.UiAutomatorUtils.getUiDevice;
+import static com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
 
 import android.Manifest;
 import android.app.Activity;
@@ -36,20 +34,16 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.icu.text.CaseMap;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.support.test.uiautomator.UiScrollable;
 import android.support.test.uiautomator.UiSelector;
-import android.support.test.uiautomator.Until;
 import android.text.Spanned;
 import android.text.style.ClickableSpan;
 import android.util.ArrayMap;
@@ -67,7 +61,6 @@
 import com.android.compatibility.common.util.UiDumpUtils;
 
 import junit.framework.Assert;
-import junit.framework.TestCase;
 
 import org.junit.Before;
 import org.junit.runner.RunWith;
@@ -76,7 +69,6 @@
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.regex.Pattern;
 
@@ -449,19 +441,27 @@
                     waitForIdle();
                 }
 
-                final boolean wasGranted = isTv() ? false : !(waitFindObject(byText(R.string.Deny)).isChecked() || (!legacyApp && waitFindObject(byText(R.string.Ask)).isChecked()));
+                final boolean wasGranted = isTv()
+                        ? false
+                        : !(waitFindObject(byText(R.string.Deny)).isChecked()
+                                || (legacyApp
+                                    && hasAskButton(permission)
+                                    && waitFindObject(byText(R.string.Ask)).isChecked()));
                 boolean alreadyChecked = false;
                 if (isTv()) {
                     waitFindObject(By.text(permissionLabel)).click();
                 } else if (state == STATE_ALLOWED) {
-                    UiObject2 object = waitFindObject(byText(R.string.Allow));
+                    UiObject2 object = waitFindObject(byText(
+                            showsForegroundOnlyButton(permission)
+                                    ? R.string.AllowForeground
+                                    : R.string.Allow));
                     alreadyChecked = object.isChecked();
                     if (!alreadyChecked) {
                         object.click();
                     }
                 } else if (state == STATE_DENIED){
                     UiObject2 object;
-                    if (legacyApp) {
+                    if (legacyApp || !hasAskButton(permission)) {
                         object = waitFindObject(byText(R.string.Deny));
                     } else {
                         object = waitFindObject(byText(R.string.Ask));
@@ -529,6 +529,19 @@
         return mPlatformResources.getString(resourceId);
     }
 
+    private boolean hasAskButton(String permission) {
+        return Manifest.permission.CAMERA.equals(permission)
+                || Manifest.permission.RECORD_AUDIO.equals(permission)
+                || Manifest.permission.ACCESS_FINE_LOCATION.equals(permission)
+                || Manifest.permission.ACCESS_COARSE_LOCATION.equals(permission)
+                || Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission);
+    }
+
+    private boolean showsForegroundOnlyButton(String permission) {
+        return Manifest.permission.CAMERA.equals(permission)
+                || Manifest.permission.RECORD_AUDIO.equals(permission);
+    }
+
     private void startActivity(final Intent intent) throws Exception {
         getInstrumentation().getUiAutomation().executeAndWaitForEvent(
                 () -> {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
index a958816..3be949d 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
@@ -285,9 +285,9 @@
     public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1() throws Exception {
         // Make sure we don't have the permission
         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
-                .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+                .checkSelfPermission(Manifest.permission.CAMERA));
 
-        String[] permissions = new String[] {Manifest.permission.READ_CALENDAR};
+        String[] permissions = new String[] {Manifest.permission.CAMERA};
 
         // Request the permission and deny it
         BasePermissionActivity.Result firstResult = requestPermissions(permissions, () -> {
@@ -300,7 +300,7 @@
 
         // Request the permission and choose don't ask again
         BasePermissionActivity.Result secondResult = requestPermissions(new String[]{
-                Manifest.permission.READ_CALENDAR}, () -> {
+                Manifest.permission.CAMERA}, () -> {
             denyWithPrejudice();
             getUiDevice().waitForIdle();
         });
@@ -309,8 +309,8 @@
         assertPermissionRequestResult(secondResult, permissions, new boolean[] {false});
 
         // Clear the denial with prejudice
-        grantPermission(Manifest.permission.READ_CALENDAR);
-        revokePermission(Manifest.permission.READ_CALENDAR);
+        grantPermission(Manifest.permission.CAMERA);
+        revokePermission(Manifest.permission.CAMERA);
 
         // We just committed a suicide by revoking the permission. See part2 below...
     }
@@ -319,17 +319,17 @@
     public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part2() throws Exception {
         // Make sure we don't have the permission
         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
-                .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+                .checkSelfPermission(Manifest.permission.CAMERA));
 
         // Request the permission and allow it
         BasePermissionActivity.Result thirdResult = requestPermissions(new String[]{
-                Manifest.permission.READ_CALENDAR}, () -> {
-            clickAllowButton();
+                Manifest.permission.CAMERA}, () -> {
+            clickAllowForegroundButton();
             getUiDevice().waitForIdle();
         });
 
         // Make sure the permission is granted
-        assertPermissionRequestResult(thirdResult, new String[] {Manifest.permission.READ_CALENDAR},
+        assertPermissionRequestResult(thirdResult, new String[] {Manifest.permission.CAMERA},
                 new boolean[] {true});
     }
 
diff --git a/hostsidetests/incident/Android.bp b/hostsidetests/incident/Android.bp
index 1589078..3a3801b 100644
--- a/hostsidetests/incident/Android.bp
+++ b/hostsidetests/incident/Android.bp
@@ -26,5 +26,6 @@
         "tradefed",
         "compatibility-host-util",
         "platformprotos",
+        "truth-prebuilt",
     ],
 }
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/Android.bp b/hostsidetests/incident/apps/graphicsstatsapp/Android.bp
index 52b5c74..c64f8a8 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/Android.bp
+++ b/hostsidetests/incident/apps/graphicsstatsapp/Android.bp
@@ -24,6 +24,7 @@
         "ctstestrunner-axt",
         "compatibility-device-util-axt",
         "androidx.legacy_legacy-support-v4",
+        "truth-prebuilt",
     ],
     sdk_version: "test_current",
     // tag this module as a cts test artifact
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml b/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml
index be9d645..88e1eaf 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml
+++ b/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml
@@ -22,6 +22,8 @@
         <uses-library android:name="android.test.runner" />
         <activity android:name=".DrawFramesActivity"
                   android:label="GraphicsStats Test Activity"
+                  android:screenOrientation="locked"
+                  android:resizeableActivity="false"
                   android:theme="@style/DefaultTheme"/>
     </application>
 
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
index 1bbc601..fd1206f 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
+++ b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
@@ -144,10 +144,6 @@
         }
     }
 
-    public void drawFrames(final int frameCount) throws InterruptedException, TimeoutException {
-        drawFrames(new int[frameCount]);
-    }
-
     public void waitForReady() throws InterruptedException, TimeoutException {
         if (!mReady.await(4, TimeUnit.SECONDS)) {
             throw new TimeoutException();
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java
index 56413f8..1a93309 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java
+++ b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java
@@ -15,13 +15,14 @@
  */
 package com.android.server.cts.device.graphicsstats;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.google.common.collect.Range;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -38,25 +39,37 @@
     public ActivityTestRule<DrawFramesActivity> mActivityRule =
             new ActivityTestRule<>(DrawFramesActivity.class);
 
-    @Test
-    public void testDrawTenFrames() throws Throwable {
+    void runTest(final int frameCount) throws Throwable {
+        runTest(new int[frameCount]);
+    }
+
+    void runTest(final int[] framesToDraw) throws Throwable {
         DrawFramesActivity activity = mActivityRule.getActivity();
         activity.waitForReady();
         int initialFrames = activity.getRenderedFramesCount();
-        assertTrue(initialFrames < 5);
-        assertEquals(0, activity.getDroppedReportsCount());
-        activity.drawFrames(10);
-        assertEquals(initialFrames + 10, activity.getRenderedFramesCount());
-        assertEquals(0, activity.getDroppedReportsCount());
+        assertThat(initialFrames).isLessThan(5);
+        assertThat(activity.getDroppedReportsCount()).isEqualTo(0);
+        activity.drawFrames(framesToDraw);
+        final int expectedFrameCount = initialFrames + framesToDraw.length;
+        assertThat(activity.getRenderedFramesCount()).isIn(
+                Range.closedOpen(expectedFrameCount, expectedFrameCount + 5));
+        assertThat(activity.getDroppedReportsCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void testNothing() throws Throwable {
+        DrawFramesActivity activity = mActivityRule.getActivity();
+        activity.waitForReady();
+        activity.drawFrames(new int[10]);
+    }
+
+    @Test
+    public void testDrawTenFrames() throws Throwable {
+        runTest(10);
     }
 
     @Test
     public void testDrawJankyFrames() throws Throwable {
-        DrawFramesActivity activity = mActivityRule.getActivity();
-        activity.waitForReady();
-        int initialFrames = activity.getRenderedFramesCount();
-        assertTrue(initialFrames < 5);
-        assertEquals(0, activity.getDroppedReportsCount());
         int[] frames = new int[50];
         for (int i = 0; i < 10; i++) {
             int indx = i * 5;
@@ -65,26 +78,17 @@
             frames[indx + 2] = DrawFramesActivity.FRAME_JANK_LAYOUT;
             frames[indx + 3] = DrawFramesActivity.FRAME_JANK_MISS_VSYNC;
         }
-        activity.drawFrames(frames);
-        assertEquals(initialFrames + 50, activity.getRenderedFramesCount());
-        assertEquals(0, activity.getDroppedReportsCount());
+        runTest(frames);
     }
 
     @Test
     public void testDrawDaveyFrames() throws Throwable {
-        DrawFramesActivity activity = mActivityRule.getActivity();
-        activity.waitForReady();
-        int initialFrames = activity.getRenderedFramesCount();
-        assertTrue(initialFrames < 5);
-        assertEquals(0, activity.getDroppedReportsCount());
         int[] frames = new int[40];
         for (int i = 0; i < 10; i++) {
             int indx = i * 4;
             frames[indx] = DrawFramesActivity.FRAME_JANK_DAVEY;
             frames[indx + 2] = DrawFramesActivity.FRAME_JANK_DAVEY_JR;
         }
-        activity.drawFrames(frames);
-        assertEquals(initialFrames + 40, activity.getRenderedFramesCount());
-        assertEquals(0, activity.getDroppedReportsCount());
+        runTest(frames);
     }
 }
diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
index ea1f803..843531d 100644
--- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
@@ -15,12 +15,14 @@
  */
 package com.android.server.cts;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.service.GraphicsStatsHistogramBucketProto;
 import android.service.GraphicsStatsJankSummaryProto;
 import android.service.GraphicsStatsProto;
 import android.service.GraphicsStatsServiceDumpProto;
 
-import com.android.tradefed.log.LogUtil.CLog;
+import com.google.common.collect.Range;
 
 import java.util.ArrayList;
 import java.util.Date;
@@ -46,7 +48,7 @@
         turnScreenOn();
         // Ensure that we have a starting point for our stats
         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".SimpleDrawFrameTests",
-                "testDrawTenFrames");
+                "testNothing");
         // Kill to ensure that stats persist/merge across process death
         killTestApp();
     }
@@ -91,24 +93,24 @@
         int jankyDelta = summaryAfter.getJankyFrames() - summaryBefore.getJankyFrames();
         // Test draws 50 frames + 1 initial frame. We expect 40 of them to be janky,
         // 10 of each of ANIMATION, LAYOUT, RECORD_DRAW, and MISSED_VSYNC
-        assertTrue(frameDelta < 55);
-        assertTrue(jankyDelta >= 40);
-        assertTrue(jankyDelta < 45);
+
+        assertThat(frameDelta).isAtLeast(50);
+        assertThat(jankyDelta).isAtLeast(40);
+        assertThat(jankyDelta).isLessThan(45);
 
         // Although our current stats don't distinguish between ANIMATION, LAYOUT, and RECORD_DRAW
         // so this will just be slowUi +30
         int slowUiDelta = summaryAfter.getSlowUiThreadCount() - summaryBefore.getSlowUiThreadCount();
-        assertTrue(slowUiDelta >= 30);
+        assertThat(slowUiDelta).isAtLeast(28);
         int missedVsyncDelta = summaryAfter.getMissedVsyncCount()
                 - summaryBefore.getMissedVsyncCount();
-        assertTrue(missedVsyncDelta >= 10);
-        assertTrue(missedVsyncDelta <= 11);
+        assertThat(missedVsyncDelta).isIn(Range.closed(10, 11));
 
         int veryJankyDelta = countFramesAbove(statsAfter, 60) - countFramesAbove(statsBefore, 60);
         // The 1st frame could be >40ms, but nothing after that should be
-        assertTrue(veryJankyDelta <= 2);
+        assertThat(veryJankyDelta).isAtMost(2);
         int noGPUJank = countGPUFramesAbove(statsAfter, 60) - countGPUFramesAbove(statsBefore, 60);
-        assertTrue(noGPUJank == 0);
+        assertThat(noGPUJank).isEqualTo(0);
     }
 
     public void testDaveyDrawFrame() throws Exception {
@@ -123,13 +125,12 @@
         int jankyDelta = summaryAfter.getJankyFrames() - summaryBefore.getJankyFrames();
         // Test draws 40 frames + 1 initial frame. We expect 10 of them to be daveys,
         // 10 of them to be daveyjrs, and 20 to jank from missed vsync (from the davey/daveyjr prior to it)
-        assertTrue(frameDelta < 45);
-        assertTrue(jankyDelta >= 20);
-        assertTrue(jankyDelta < 25);
+        assertThat(frameDelta).isAtLeast(40);
+        assertThat(jankyDelta).isAtLeast(20);
+        assertThat(jankyDelta).isLessThan(25);
 
         int gt150msDelta = countFramesAbove(statsAfter, 150) - countFramesAbove(statsBefore, 150);
-        assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first 2 frames
-        assertTrue(gt150msDelta <= 22);
+        assertThat(gt150msDelta).isIn(Range.closed(20, 22));
         int gt700msDelta = countFramesAbove(statsAfter, 700) - countFramesAbove(statsBefore, 700);
         assertEquals(10, gt700msDelta); // 10 daveys
     }
@@ -139,10 +140,10 @@
     }
 
     private GraphicsStatsProto[] doRunDrawTest(String testName, boolean canRetry) throws Exception {
-        GraphicsStatsProto statsBefore = fetchStats();
-        assertNotNull(statsBefore);
         killTestApp();
         turnScreenOn();
+        GraphicsStatsProto statsBefore = fetchStats();
+        assertNotNull(statsBefore);
         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".SimpleDrawFrameTests",  testName);
         killTestApp();
         GraphicsStatsProto statsAfter = fetchStats();
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
index ef0a5cb..1a7e5b6 100755
--- a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
@@ -49,6 +49,8 @@
         case InputMessage::Type::KEY: {
             // uint32_t seq
             outMsg->body.key.seq = msg.body.key.seq;
+            // int32_t eventId
+            outMsg->body.key.eventId = msg.body.key.eventId;
             // nsecs_t eventTime
             outMsg->body.key.eventTime = msg.body.key.eventTime;
             // int32_t deviceId
@@ -78,6 +80,8 @@
         case InputMessage::Type::MOTION: {
             // uint32_t seq
             outMsg->body.motion.seq = msg.body.motion.seq;
+            // int32_t eventId
+            outMsg->body.motion.eventId = msg.body.key.eventId;
             // nsecs_t eventTime
             outMsg->body.motion.eventTime = msg.body.motion.eventTime;
             // int32_t deviceId
@@ -146,6 +150,7 @@
         }
         case InputMessage::Type::FOCUS: {
             outMsg->body.focus.seq = msg.body.focus.seq;
+            outMsg->body.focus.eventId = msg.body.focus.eventId;
             outMsg->body.focus.hasFocus = msg.body.focus.hasFocus;
             outMsg->body.focus.inTouchMode = msg.body.focus.inTouchMode;
             break;
diff --git a/tests/accessibility/res/drawable/size_48x48.jpg b/tests/accessibility/res/drawable/jpg_48_48.jpg
similarity index 100%
rename from tests/accessibility/res/drawable/size_48x48.jpg
rename to tests/accessibility/res/drawable/jpg_48_48.jpg
Binary files differ
diff --git a/tests/accessibility/res/drawable/png_72_72.png b/tests/accessibility/res/drawable/png_72_72.png
new file mode 100644
index 0000000..941458d
--- /dev/null
+++ b/tests/accessibility/res/drawable/png_72_72.png
Binary files differ
diff --git a/tests/accessibility/res/drawable/vector_drawable_6kdp_6kdp.xml b/tests/accessibility/res/drawable/vector_drawable_6kdp_6kdp.xml
new file mode 100644
index 0000000..0d11dc0
--- /dev/null
+++ b/tests/accessibility/res/drawable/vector_drawable_6kdp_6kdp.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="6000dp"
+        android:height="6000dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2 -0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
+</vector>
diff --git a/tests/accessibility/res/raw/test_file b/tests/accessibility/res/raw/test_file
new file mode 100644
index 0000000..acea7ed
--- /dev/null
+++ b/tests/accessibility/res/raw/test_file
@@ -0,0 +1,12 @@
+10101010110101010101101010101011010101010110101010101101010101011010101010110
+1010101011010101010110101010101101010101011010101011010101101101010101011011011010101101101
+1011010101010011010101010110101011011010101010110101011011010101010110110110101010101101
+10110101010101101010101011010101010110101010101101010101010101101010101011010101
+101101010101011010101010110101010101101010101011010101101011010101010110101010101101010101011010101
+101101010101101010101011010101101101010101011010101001010110101011011010101010110110101010101
+10110101010101101010101011010101010110101010101101010101010101101
+101101010101010110101010101101010110110101010101101010101011010101011101010101011010101101101010
+10110101010101011010101101101010101011010101101010101011010101101010101011010101
+101101010101011010101011010101010110101011011010101010110101010101101010101
+
+
diff --git a/tests/accessibility/res/values/strings.xml b/tests/accessibility/res/values/strings.xml
index de1539a..40c3359 100644
--- a/tests/accessibility/res/values/strings.xml
+++ b/tests/accessibility/res/values/strings.xml
@@ -32,8 +32,26 @@
     <!-- Description of the speaking accessibility service -->
     <string name="some_description">Some description</string>
 
+    <!-- Html description of the vibrating accessibility service -->
+    <string name="html_description_vibrating_accessibility_service"><![CDATA[
+    <A href=\"fake_link\">Test link</a> <IMG src = \"R.drawable.file_name\">
+    ]]></string>
+
     <!-- Html description of the speaking accessibility service -->
-    <string name="some_html_description">Some html description</string>
+    <string name="html_description_speaking_accessibility_service"><![CDATA[
+    <a href=\"fake_link\"> <img src=\"R.drawable.file_name\">
+    ]]></string>
+
+    <!-- Html description of the speaking and vibrating accessibility service -->
+    <string name="html_description_speaking_and_vibrating_accessibility_service"><![CDATA[
+    <a href=fake_link> <img src=R.drawable.file_name>
+    ]]></string>
+
+    <!-- Html description of the accessibility button service -->
+    <string name="html_description_accessibility_button_service"><![CDATA[
+    <img src=\"r.drawable.file_name\"> <img alt=\"foo\" src=\"R.drawable.file_name\">
+    <img src=\"file://path\"> <img src=\"http://path\">
+    ]]></string>
 
     <!-- Summary of the speaking accessibility service -->
     <string name="some_summary">Some summary</string>
diff --git a/tests/accessibility/res/xml/accessibility_button_service.xml b/tests/accessibility/res/xml/accessibility_button_service.xml
index d475266..e483fd4 100644
--- a/tests/accessibility/res/xml/accessibility_button_service.xml
+++ b/tests/accessibility/res/xml/accessibility_button_service.xml
@@ -18,4 +18,6 @@
                        android:accessibilityEventTypes="typeAllMask"
                        android:accessibilityFeedbackType="feedbackGeneric"
                        android:accessibilityFlags="flagRequestAccessibilityButton"
+                       android:animatedImageDrawable="@raw/test_file"
+                       android:htmlDescription="@string/html_description_accessibility_button_service"
                        android:notificationTimeout="0" />
\ No newline at end of file
diff --git a/tests/accessibility/res/xml/speaking_accessibilityservice.xml b/tests/accessibility/res/xml/speaking_accessibilityservice.xml
index ede686d..9128309 100644
--- a/tests/accessibility/res/xml/speaking_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/speaking_accessibilityservice.xml
@@ -21,9 +21,9 @@
     android:canRequestTouchExplorationMode="true"
     android:canRequestFilterKeyEvents="true"
     android:settingsActivity="foo.bar.Activity"
-    android:animatedImageDrawable="@drawable/size_48x48"
+    android:animatedImageDrawable="@drawable/jpg_48_48"
     android:description="@string/some_description"
-    android:htmlDescription="@string/some_html_description"
+    android:htmlDescription="@string/html_description_speaking_accessibility_service"
     android:summary="@string/some_summary"
     android:nonInteractiveUiTimeout="1000"
     android:interactiveUiTimeout="6000"/>
\ No newline at end of file
diff --git a/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml b/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml
index 3ac8661..09d36c6 100644
--- a/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml
@@ -22,7 +22,7 @@
     android:canRequestFilterKeyEvents="true"
     android:canRequestEnhancedWebAccessibility="true"
     android:settingsActivity="foo.bar.Activity"
-    android:animatedImageDrawable="@drawable/size_48x48"
+    android:animatedImageDrawable="@drawable/vector_drawable_6kdp_6kdp"
     android:description="@string/some_description"
-    android:htmlDescription="@string/some_html_description"
+    android:htmlDescription="@string/html_description_speaking_and_vibrating_accessibility_service"
     android:summary="@string/some_summary" />
diff --git a/tests/accessibility/res/xml/vibrating_accessibilityservice.xml b/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
index 93d9f0d..ddf4018 100644
--- a/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
@@ -20,4 +20,6 @@
     android:canRetrieveWindowContent="true"
     android:canRequestTouchExplorationMode="true"
     android:nonInteractiveUiTimeout="2000"
+    android:animatedImageDrawable="@drawable/png_72_72"
+    android:htmlDescription="@string/html_description_vibrating_accessibility_service"
     android:interactiveUiTimeout="5000"/>
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
index d2f7c2d..8a75b54 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
@@ -19,6 +19,7 @@
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
@@ -26,13 +27,16 @@
 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
 import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.app.Service;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -49,22 +53,44 @@
  */
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityServiceInfoTest {
+    private AccessibilityManager mAccessibilityManager;
+    private PackageManager mPackageManager;
+    private Context mContext;
 
-    private InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService>
+    private final InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService>
             mSpeakingAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
-                    SpeakingAccessibilityService.class);
+            SpeakingAccessibilityService.class);
 
-    private InstrumentedAccessibilityServiceTestRule<VibratingAccessibilityService>
+    private final InstrumentedAccessibilityServiceTestRule<VibratingAccessibilityService>
             mVibratingAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
-                    VibratingAccessibilityService.class);
+            VibratingAccessibilityService.class);
+
+    private final InstrumentedAccessibilityServiceTestRule<SpeakingAndVibratingAccessibilityService>
+            mSpeakingAndVibratingAccessibilityServiceRule =
+            new InstrumentedAccessibilityServiceTestRule<>(
+                    SpeakingAndVibratingAccessibilityService.class, /* enableService= */ false);
+
+    private final InstrumentedAccessibilityServiceTestRule<AccessibilityButtonService>
+            mA11yButtonServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
+            AccessibilityButtonService.class, /* enableService= */ false);
 
     @Rule
     public final RuleChain mRuleChain = RuleChain
             .outerRule(mVibratingAccessibilityServiceRule)
             .around(mSpeakingAccessibilityServiceRule)
+            .around(mSpeakingAndVibratingAccessibilityServiceRule)
+            .around(mA11yButtonServiceRule)
             // Inner rule capture failure and dump data before finishing a11y service
             .around(new AccessibilityDumpOnFailureRule());
 
+    @Before
+    public void setUp() throws Exception {
+        mContext = getInstrumentation().getContext();
+        mAccessibilityManager = getInstrumentation().getContext().getSystemService(
+                AccessibilityManager.class);
+        mPackageManager = getInstrumentation().getContext().getPackageManager();
+    }
+
     /**
      * Tests whether a service can that requested it can retrieve
      * window content.
@@ -73,13 +99,12 @@
     @SuppressWarnings("deprecation")
     @Test
     public void testAccessibilityServiceInfoForEnabledService() {
-        AccessibilityManager accessibilityManager = (AccessibilityManager)
-                getInstrumentation().getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
-        List<AccessibilityServiceInfo> enabledServices =
-            accessibilityManager.getEnabledAccessibilityServiceList(
-                    AccessibilityServiceInfo.FEEDBACK_SPOKEN);
-        assertSame("There should be one speaking service.", 1, enabledServices.size());
-        AccessibilityServiceInfo speakingService = enabledServices.get(0);
+        final List<AccessibilityServiceInfo> enabledServices =
+                mAccessibilityManager.getEnabledAccessibilityServiceList(
+                        AccessibilityServiceInfo.FEEDBACK_SPOKEN);
+        assertSame(/* message= */ "There should be one speaking service.",
+                /* expected= */ 1, enabledServices.size());
+        final AccessibilityServiceInfo speakingService = enabledServices.get(0);
         assertSame(AccessibilityEvent.TYPES_ALL_MASK, speakingService.eventTypes);
         assertSame(AccessibilityServiceInfo.FEEDBACK_SPOKEN, speakingService.feedbackType);
         assertEquals(AccessibilityServiceInfo.DEFAULT
@@ -89,8 +114,8 @@
                 | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
                 | AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK,
                 speakingService.flags);
-        assertSame(0l, speakingService.notificationTimeout);
-        assertEquals("Some description", speakingService.getDescription());
+        assertSame(/* expected= */ 0l, speakingService.notificationTimeout);
+        assertEquals(/* expected= */ "Some description", speakingService.getDescription());
         assertNull(speakingService.packageNames /*all packages*/);
         assertNotNull(speakingService.getId());
         assertSame(speakingService.getCapabilities(),
@@ -98,15 +123,86 @@
                 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
                 | AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
         assertEquals("foo.bar.Activity", speakingService.getSettingsActivityName());
-        assertNotNull(speakingService.loadAnimatedImage(getInstrumentation().getContext()));
-        assertEquals("Some description", speakingService.loadDescription(
-                getInstrumentation().getContext().getPackageManager()));
-        assertEquals("Some html description", speakingService.loadHtmlDescription(
-                getInstrumentation().getContext().getPackageManager()));
-        assertEquals("Some summary", speakingService.loadSummary(
-                getInstrumentation().getContext().getPackageManager()));
+        assertNotNull(speakingService.loadAnimatedImage(mContext));
+        assertEquals(/* expected= */ "Some description",
+                speakingService.loadDescription(mPackageManager));
+        assertEquals(/* expected= */
+                "<invalidtag href=\"fake_link\"> <img src=\"R.drawable.file_name\">",
+                speakingService.loadHtmlDescription(mPackageManager));
+        assertEquals(/* expected= */ "Some summary",
+                speakingService.loadSummary(mPackageManager));
         assertNotNull(speakingService.getResolveInfo());
-        assertEquals(6000, speakingService.getInteractiveUiTimeoutMillis());
-        assertEquals(1000, speakingService.getNonInteractiveUiTimeoutMillis());
+        assertEquals(/* expected= */ 6000,
+                speakingService.getInteractiveUiTimeoutMillis());
+        assertEquals(/* expected= */ 1000,
+                speakingService.getNonInteractiveUiTimeoutMillis());
+    }
+
+    /**
+     * Tests the html description of accessibility services whether to meet the custom
+     * specification.
+     */
+    @Test
+    public void testAccessibilityServicesHtmlDescription() {
+        mSpeakingAndVibratingAccessibilityServiceRule.enableService();
+        mA11yButtonServiceRule.enableService();
+        final List<AccessibilityServiceInfo> enabledServices =
+                mAccessibilityManager.getEnabledAccessibilityServiceList(
+                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+        final AccessibilityServiceInfo vibratingService =
+                mVibratingAccessibilityServiceRule.getService().getServiceInfo();
+        final AccessibilityServiceInfo speakingService =
+                mSpeakingAccessibilityServiceRule.getService().getServiceInfo();
+        final AccessibilityServiceInfo speakingAndVibratingService =
+                mSpeakingAndVibratingAccessibilityServiceRule.getService().getServiceInfo();
+        final AccessibilityServiceInfo a11yService =
+                mA11yButtonServiceRule.getService().getServiceInfo();
+
+        assertSame(/* message= */ "There should be four services.", /* expected= */ 4,
+                enabledServices.size());
+        assertEquals(/* expected= */
+                "<invalidtag href=\"fake_link\">Test link</invalidtag> "
+                        + "<IMG src = \"R.drawable.file_name\">",
+                vibratingService.loadHtmlDescription(mPackageManager));
+        assertEquals(/* expected= */
+                "<invalidtag href=\"fake_link\"> <img src=\"R.drawable.file_name\">",
+                speakingService.loadHtmlDescription(mPackageManager));
+        assertEquals(/* expected= */
+                "<invalidtag href=fake_link> <invalidtag src=R.drawable.file_name>",
+                speakingAndVibratingService.loadHtmlDescription(mPackageManager));
+        assertEquals(/* expected= */
+                "<invalidtag src=\"r.drawable.file_name\"> "
+                        + "<invalidtag alt=\"foo\" src=\"R.drawable.file_name\"> "
+                        + "<invalidtag src=\"file://path\"> "
+                        + "<invalidtag src=\"http://path\">",
+                a11yService.loadHtmlDescription(mPackageManager));
+    }
+
+    /**
+     * Tests the animated image resource of accessibility services whether to meet the custom
+     * specification.
+     */
+    @Test
+    public void testAccessibilityServicesAnimatedImageResource() {
+        mSpeakingAndVibratingAccessibilityServiceRule.enableService();
+        mA11yButtonServiceRule.enableService();
+        final List<AccessibilityServiceInfo> enabledServices =
+                mAccessibilityManager.getEnabledAccessibilityServiceList(
+                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+        final AccessibilityServiceInfo vibratingService =
+                mVibratingAccessibilityServiceRule.getService().getServiceInfo();
+        final AccessibilityServiceInfo speakingService =
+                mSpeakingAccessibilityServiceRule.getService().getServiceInfo();
+        final AccessibilityServiceInfo speakingAndVibratingService =
+                mSpeakingAndVibratingAccessibilityServiceRule.getService().getServiceInfo();
+        final AccessibilityServiceInfo a11yService =
+                mA11yButtonServiceRule.getService().getServiceInfo();
+
+        assertSame(/* message= */ "There should be four services.", /* expected= */ 4,
+                enabledServices.size());
+        assertNotNull(vibratingService.loadAnimatedImage(mContext));
+        assertNotNull(speakingService.loadAnimatedImage(mContext));
+        assertNull(speakingAndVibratingService.loadAnimatedImage(mContext));
+        assertNull(a11yService.loadAnimatedImage(mContext));
     }
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
index 4111baf..8f79102 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
@@ -18,6 +18,7 @@
 
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -69,6 +70,8 @@
     private final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
             new AccessibilityDumpOnFailureRule();
 
+    private AccessibilityEmbeddedHierarchyActivity mActivity;
+
     @Rule
     public final RuleChain mRuleChain = RuleChain
             .outerRule(mActivityRule)
@@ -90,8 +93,9 @@
 
     @Before
     public void setUp() throws Throwable {
-        launchActivityAndWaitForItToBeOnscreen(sInstrumentation, sUiAutomation, mActivityRule)
-                .waitForEmbeddedHierarchy();
+        mActivity = launchActivityAndWaitForItToBeOnscreen(sInstrumentation, sUiAutomation,
+                mActivityRule);
+        mActivity.waitForEmbeddedHierarchy();
     }
 
     @Test
@@ -114,6 +118,7 @@
         final AccessibilityNodeInfo target =
                 findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
         final AccessibilityNodeInfo parent = target.getParent();
+
         final Rect hostViewBoundsInScreen = new Rect();
         final Rect embeddedViewBoundsInScreen = new Rect();
         parent.getBoundsInScreen(hostViewBoundsInScreen);
@@ -125,6 +130,36 @@
                 hostViewBoundsInScreen.contains(embeddedViewBoundsInScreen));
     }
 
+    @Test
+    public void testEmbeddedViewHasCorrectBoundAfterHostViewMove() {
+        final AccessibilityNodeInfo target =
+                findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+
+        final Rect hostViewBoundsInScreen = new Rect();
+        final Rect newEmbeddedViewBoundsInScreen = new Rect();
+        final Rect oldEmbeddedViewBoundsInScreen = new Rect();
+        target.getBoundsInScreen(oldEmbeddedViewBoundsInScreen);
+
+        // Move Host SurfaceView from (0, 0) to (100, 100).
+        mActivity.requestNewLayoutForTest();
+
+        final AccessibilityNodeInfo newTarget =
+                findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+        final AccessibilityNodeInfo parent = newTarget.getParent();
+
+        newTarget.getBoundsInScreen(newEmbeddedViewBoundsInScreen);
+        parent.getBoundsInScreen(hostViewBoundsInScreen);
+
+        assertTrue("hostViewBoundsInScreen" + hostViewBoundsInScreen.toShortString()
+                        + " doesn't contain newEmbeddedViewBoundsInScreen"
+                        + newEmbeddedViewBoundsInScreen.toShortString(),
+                hostViewBoundsInScreen.contains(newEmbeddedViewBoundsInScreen));
+        assertFalse("newEmbeddedViewBoundsInScreen" + newEmbeddedViewBoundsInScreen.toShortString()
+                        + " shouldn't be the same with oldEmbeddedViewBoundsInScreen"
+                        + oldEmbeddedViewBoundsInScreen.toShortString(),
+                newEmbeddedViewBoundsInScreen.equals(oldEmbeddedViewBoundsInScreen));
+    }
+
     private AccessibilityNodeInfo findEmbeddedAccessibilityNodeInfo(AccessibilityNodeInfo root) {
         final int childCount = root.getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -150,8 +185,11 @@
             AccessibilityTestActivity implements SurfaceHolder.Callback {
         private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
 
-        private static final int DEFAULT_WIDTH = 200;
-        private static final int DEFAULT_HEIGHT = 200;
+        private static final int DEFAULT_WIDTH = 150;
+        private static final int DEFAULT_HEIGHT = 150;
+
+        private static final int POSITION_X = 50;
+        private static final int POSITION_Y = 50;
 
         private SurfaceView mSurfaceView;
         private SurfaceControlViewHost mViewHost;
@@ -195,5 +233,13 @@
                 throw new AssertionError(e);
             }
         }
+
+        public void requestNewLayoutForTest() {
+            sInstrumentation.runOnMainSync(() -> {
+                mSurfaceView.setX(POSITION_X);
+                mSurfaceView.setY(POSITION_Y);
+                mSurfaceView.requestLayout();
+            });
+        }
     }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java
new file mode 100644
index 0000000..678bad0
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 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.inline;
+
+import static android.app.Activity.RESULT_OK;
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.UNUSED_AUTOFILL_VALUE;
+import static android.autofillservice.cts.Helper.getContext;
+import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
+import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
+
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.autofillservice.cts.AbstractLoginActivityTestCase;
+import android.autofillservice.cts.AuthenticationActivity;
+import android.autofillservice.cts.CannedFillResponse;
+import android.autofillservice.cts.Helper;
+import android.content.IntentSender;
+import android.os.Process;
+
+import com.android.cts.mockime.ImeEventStream;
+import com.android.cts.mockime.MockImeSession;
+
+import org.junit.Test;
+
+public class InlineAuthenticationTest extends AbstractLoginActivityTestCase {
+
+    private static final String TAG = "InlineAuthenticationTest";
+
+    @Override
+    protected void enableService() {
+        Helper.enableAutofillService(getContext(), SERVICE_NAME);
+    }
+
+    @Test
+    public void testDatasetAuthTwoFields() throws Exception {
+        datasetAuthTwoFields(/* cancelFirstAttempt */ false);
+    }
+
+    private void datasetAuthTwoFields(boolean cancelFirstAttempt) throws Exception {
+        // Set service.
+        enableService();
+
+        final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
+        assumeTrue("MockIME not available", mockImeSession != null);
+
+        // Prepare the authenticated response
+        final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+                new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_USERNAME, "dude")
+                        .setField(ID_PASSWORD, "sweet")
+                        .build());
+        final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+                        .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+                        .setPresentation(createPresentation("auth"))
+                        .setInlinePresentation(createInlinePresentation("auth"))
+                        .setAuthentication(authentication)
+                        .build());
+        sReplier.addResponse(builder.build());
+        mActivity.expectAutoFill("dude", "sweet");
+
+        final ImeEventStream stream = mockImeSession.openEventStream();
+        mockImeSession.callRequestShowSelf(0);
+
+        // Wait until the MockIme gets bound to the TestActivity.
+        expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
+
+        // Trigger auto-fill.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdle();
+        sReplier.getNextFillRequest();
+        mUiBot.assertSuggestionStrip(1);
+
+        // Make sure UI is show on 2nd field as well
+        mUiBot.selectByRelativeId(ID_PASSWORD);
+        mUiBot.waitForIdle();
+        mUiBot.assertSuggestionStrip(1);
+
+        // Now tap on 1st field to show it again...
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdle();
+        mUiBot.assertSuggestionStrip(1);
+
+        // TODO(b/149891961): add logic for cancelFirstAttempt
+
+        // ...and select it this time
+        AuthenticationActivity.setResultCode(RESULT_OK);
+        mUiBot.selectSuggestion(0);
+        mUiBot.waitForIdle();
+
+        // Check the results.
+        mActivity.assertAutoFilled();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFillEventHistoryTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFillEventHistoryTest.java
new file mode 100644
index 0000000..941ebe2
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFillEventHistoryTest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2020 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.inline;
+
+import static android.autofillservice.cts.CannedFillResponse.DO_NOT_REPLY_RESPONSE;
+import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.NULL_DATASET_ID;
+import static android.autofillservice.cts.Helper.assertFillEventForDatasetAuthenticationSelected;
+import static android.autofillservice.cts.Helper.assertFillEventForDatasetSelected;
+import static android.autofillservice.cts.Helper.assertFillEventForDatasetShown;
+import static android.autofillservice.cts.Helper.assertFillEventForSaveShown;
+import static android.autofillservice.cts.Helper.assertNoDeprecatedClientState;
+import static android.autofillservice.cts.Helper.getContext;
+import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilConnected;
+import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilDisconnected;
+import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import android.autofillservice.cts.AbstractLoginActivityTestCase;
+import android.autofillservice.cts.AuthenticationActivity;
+import android.autofillservice.cts.CannedFillResponse;
+import android.autofillservice.cts.CannedFillResponse.CannedDataset;
+import android.autofillservice.cts.Helper;
+import android.autofillservice.cts.InstrumentedAutoFillService;
+import android.autofillservice.cts.LoginActivity;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
+import android.service.autofill.FillEventHistory;
+import android.service.autofill.FillEventHistory.Event;
+import android.support.test.uiautomator.UiObject2;
+import android.view.View;
+
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * Test that uses {@link LoginActivity} to test {@link FillEventHistory}.
+ */
+@AppModeFull(reason = "Service-specific test")
+public class InlineFillEventHistoryTest extends AbstractLoginActivityTestCase {
+
+    @Override
+    protected void enableService() {
+        Helper.enableAutofillService(getContext(), SERVICE_NAME);
+    }
+
+    @Test
+    public void testNoDatasetAndSave() throws Exception {
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_USERNAME)
+                .build());
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdle();
+
+        sReplier.getNextFillRequest();
+
+        // Suggestion strip was never shown.
+        mUiBot.assertNoSuggestionStripEver();
+
+        // Change username
+        mActivity.syncRunOnUiThread(() ->  mActivity.onUsername((v) -> v.setText("ID")));
+        mUiBot.waitForIdle();
+
+        // Trigger save UI.
+        mActivity.tapSave();
+        mUiBot.waitForIdle();
+
+        // Confirm the save UI shown
+        final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+        // Save it...
+        mUiBot.saveForAutofill(saveUi, true);
+        mUiBot.waitForIdle();
+        sReplier.getNextSaveRequest();
+
+        // Verify save event
+        final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(1);
+        assertNoDeprecatedClientState(selection);
+        final List<Event> events = selection.getEvents();
+        assertFillEventForSaveShown(events.get(0), NULL_DATASET_ID);
+    }
+
+    @Test
+    public void testOneDatasetAndSave() throws Exception {
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_USERNAME)
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "id")
+                        .setField(ID_PASSWORD, "pass")
+                        .setPresentation(createPresentation("Dataset"))
+                        .setInlinePresentation(createInlinePresentation("Dataset"))
+                        .build())
+                .build());
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdle();
+        sReplier.getNextFillRequest();
+
+        // Suggestion strip was shown.
+        mUiBot.assertSuggestionStrip(1);
+        mUiBot.waitForIdle();
+
+        mUiBot.selectSuggestion(0);
+
+        // Change username and password
+        mActivity.syncRunOnUiThread(() ->  mActivity.onUsername((v) -> v.setText("ID")));
+        mActivity.syncRunOnUiThread(() ->  mActivity.onPassword((v) -> v.setText("PASS")));
+        mUiBot.waitForIdle();
+
+        // Trigger save UI.
+        mActivity.tapSave();
+        mUiBot.waitForIdle();
+
+        // Confirm the save UI shown
+        final UiObject2 saveUi = mUiBot.assertUpdateShowing(SAVE_DATA_TYPE_GENERIC);
+
+        // Save it...
+        mUiBot.saveForAutofill(saveUi, true);
+        mUiBot.waitForIdle();
+        sReplier.getNextSaveRequest();
+
+        // Verify events history
+        final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(4);
+        assertNoDeprecatedClientState(selection);
+        final List<Event> events = selection.getEvents();
+        assertFillEventForDatasetShown(events.get(0));
+        assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+        assertFillEventForDatasetShown(events.get(0));
+        assertFillEventForSaveShown(events.get(3), NULL_DATASET_ID);
+    }
+
+    @Test
+    public void testDatasetAuthenticationSelected() throws Exception {
+        enableService();
+
+        // Set up FillResponse with dataset authentication
+        Bundle clientState = new Bundle();
+        clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+        // Prepare the authenticated response
+        final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "dude")
+                        .setField(ID_PASSWORD, "sweet")
+                        .setPresentation(createPresentation("Dataset"))
+                        .setInlinePresentation(createInlinePresentation("Dataset"))
+                        .build());
+
+        sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "username")
+                        .setId("name")
+                        .setPresentation(createPresentation("authentication"))
+                        .setInlinePresentation(createInlinePresentation("authentication"))
+                        .setAuthentication(authentication)
+                        .build())
+                .setExtras(clientState).build());
+        mActivity.expectAutoFill("dude", "sweet");
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdle();
+
+        // ...
+        sReplier.getNextFillRequest();
+        mUiBot.assertSuggestionStrip(1);
+
+        // Authenticate
+        mUiBot.selectSuggestion(0);
+        mUiBot.waitForIdle();
+        mActivity.assertAutoFilled();
+
+        // Verify fill selection
+        final List<Event> events = InstrumentedAutoFillService.getFillEvents(2);
+        assertFillEventForDatasetShown(events.get(0), "clientStateKey", "clientStateValue");
+        assertFillEventForDatasetAuthenticationSelected(events.get(1), "name",
+                "clientStateKey", "clientStateValue");
+    }
+
+    @Test
+    public void testNoEvents_whenServiceReturnsNullResponse() throws Exception {
+        enableService();
+
+        // First reset
+        sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "username")
+                        .setPresentation(createPresentation("dataset1"))
+                        .setInlinePresentation(createInlinePresentation("dataset1"))
+                        .build())
+                .build());
+        mActivity.expectAutoFill("username");
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        waitUntilConnected();
+        sReplier.getNextFillRequest();
+        mUiBot.selectSuggestion(0);
+        mUiBot.waitForIdle();
+        mActivity.assertAutoFilled();
+
+        {
+            // Verify fill selection
+            final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(2);
+            assertNoDeprecatedClientState(selection);
+            final List<Event> events = selection.getEvents();
+            assertFillEventForDatasetShown(events.get(0));
+            assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+        }
+
+        // Second request
+        sReplier.addResponse(NO_RESPONSE);
+        mActivity.onPassword(View::requestFocus);
+        sReplier.getNextFillRequest();
+        mUiBot.assertNoSuggestionStripEver();
+        waitUntilDisconnected();
+
+        InstrumentedAutoFillService.assertNoFillEventHistory();
+    }
+
+    @Test
+    public void testNoEvents_whenServiceReturnsFailure() throws Exception {
+        enableService();
+
+        // First reset
+        sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "username")
+                        .setPresentation(createPresentation("dataset1"))
+                        .setInlinePresentation(createInlinePresentation("dataset1"))
+                        .build())
+                .build());
+        mActivity.expectAutoFill("username");
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        waitUntilConnected();
+        sReplier.getNextFillRequest();
+        mUiBot.selectSuggestion(0);
+        mUiBot.waitForIdle();
+        mActivity.assertAutoFilled();
+
+        {
+            // Verify fill selection
+            final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(2);
+            assertNoDeprecatedClientState(selection);
+            final List<Event> events = selection.getEvents();
+            assertFillEventForDatasetShown(events.get(0));
+            assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+        }
+
+        // Second request
+        sReplier.addResponse(new CannedFillResponse.Builder().returnFailure("D'OH!").build());
+        mActivity.onPassword(View::requestFocus);
+        sReplier.getNextFillRequest();
+        mUiBot.assertNoSuggestionStripEver();
+        waitUntilDisconnected();
+
+        InstrumentedAutoFillService.assertNoFillEventHistory();
+    }
+
+    @Test
+    public void testNoEvents_whenServiceTimesout() throws Exception {
+        enableService();
+
+        // First reset
+        sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "username")
+                        .setPresentation(createPresentation("dataset1"))
+                        .setInlinePresentation(createInlinePresentation("dataset1"))
+                        .build())
+                .build());
+        mActivity.expectAutoFill("username");
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        waitUntilConnected();
+        sReplier.getNextFillRequest();
+        mUiBot.selectSuggestion(0);
+        mUiBot.waitForIdle();
+        mActivity.assertAutoFilled();
+
+        {
+            // Verify fill selection
+            final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(2);
+            assertNoDeprecatedClientState(selection);
+            final List<Event> events = selection.getEvents();
+            assertFillEventForDatasetShown(events.get(0));
+            assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+        }
+
+        // Second request
+        sReplier.addResponse(DO_NOT_REPLY_RESPONSE);
+        mActivity.onPassword(View::requestFocus);
+        sReplier.getNextFillRequest();
+        waitUntilDisconnected();
+
+        InstrumentedAutoFillService.assertNoFillEventHistory();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java
new file mode 100644
index 0000000..17bcc2f
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 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.inline;
+
+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_COMMIT;
+import static android.autofillservice.cts.SimpleSaveActivity.ID_INPUT;
+import static android.autofillservice.cts.SimpleSaveActivity.ID_PASSWORD;
+import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import android.autofillservice.cts.AutoFillServiceTestCase;
+import android.autofillservice.cts.AutofillActivityTestRule;
+import android.autofillservice.cts.CannedFillResponse;
+import android.autofillservice.cts.Helper;
+import android.autofillservice.cts.InstrumentedAutoFillService;
+import android.autofillservice.cts.SimpleSaveActivity;
+import android.support.test.uiautomator.UiObject2;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+
+public class InlineSimpleSaveActivityTest
+        extends AutoFillServiceTestCase.AutoActivityLaunch<SimpleSaveActivity> {
+
+    private static final String TAG = "InlineSimpleSaveActivityTest";
+    protected SimpleSaveActivity mActivity;
+
+    @Override
+    protected void enableService() {
+        Helper.enableAutofillService(getContext(), SERVICE_NAME);
+    }
+
+    @NonNull
+    @Override
+    protected AutofillActivityTestRule<SimpleSaveActivity> getActivityRule() {
+        return new AutofillActivityTestRule<SimpleSaveActivity>(SimpleSaveActivity.class) {
+            @Override
+            protected void afterActivityLaunched() {
+                mActivity = getActivity();
+            }
+        };
+    }
+
+    @Test
+    public void testAutofillSave() throws Exception {
+        // Set service.
+        enableService();
+
+         // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT)
+                .build());
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_INPUT);
+        mUiBot.waitForIdle();
+
+        sReplier.getNextFillRequest();
+
+        // Suggestion strip was never shown.
+        mUiBot.assertNoSuggestionStripEver();
+
+        // Change input
+        mActivity.syncRunOnUiThread(() -> mActivity.getInput().setText("ID"));
+        mUiBot.waitForIdle();
+
+        // Trigger save UI.
+        mUiBot.selectByRelativeId(ID_COMMIT);
+        mUiBot.waitForIdle();
+
+        // Confirm the save UI shown
+        final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+        // Save it...
+        mUiBot.saveForAutofill(saveUi, true);
+
+        // ... and assert results
+        final InstrumentedAutoFillService.SaveRequest saveRequest = sReplier.getNextSaveRequest();
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_INPUT), "ID");
+    }
+
+    @Test
+    public void testAutofill_oneDatasetAndSave() throws Exception {
+        // Set service.
+        enableService();
+
+        final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT, ID_PASSWORD)
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_INPUT, "id")
+                        .setField(ID_PASSWORD, "pass")
+                        .setPresentation(createPresentation("YO"))
+                        .setInlinePresentation(createInlinePresentation("YO"))
+                        .build());
+        sReplier.addResponse(builder.build());
+        mActivity.expectAutoFill("id", "pass");
+
+        // Trigger auto-fill and IME.
+        mUiBot.selectByRelativeId(ID_INPUT);
+        mUiBot.waitForIdle();
+
+        sReplier.getNextFillRequest();
+
+        // Confirm one suggestion
+        mUiBot.assertSuggestionStrip(1);
+
+        // Select suggestion
+        mUiBot.selectSuggestion(0);
+        mUiBot.waitForIdle();
+
+        // Check the results.
+        mActivity.expectAutoFill("id", "pass");
+
+        // Change input
+        mActivity.syncRunOnUiThread(() -> mActivity.getInput().setText("ID"));
+        mUiBot.waitForIdle();
+
+        // Trigger save UI.
+        mUiBot.selectByRelativeId(ID_COMMIT);
+        mUiBot.waitForIdle();
+
+        // Confirm the save UI shown
+        final UiObject2 saveUi = mUiBot.assertUpdateShowing(SAVE_DATA_TYPE_GENERIC);
+
+        // Save it...
+        mUiBot.saveForAutofill(saveUi, true);
+
+        // ... and assert results
+        final InstrumentedAutoFillService.SaveRequest saveRequest = sReplier.getNextSaveRequest();
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_INPUT), "ID");
+        assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_PASSWORD), "pass");
+    }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index c454c84..5121a39 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -292,7 +292,6 @@
      * Tests launching a single instance home activity on virtual display with system decoration
      * support.
      */
-    @FlakyTest(bugId = 149070587)
     @Test
     public void testLaunchSingleHomeActivityOnDisplayWithDecorations() {
         createManagedHomeActivitySession(SINGLE_HOME_ACTIVITY);
@@ -316,7 +315,6 @@
      * Tests launching a single instance home activity with SECONDARY_HOME on virtual display with
      * system decoration support.
      */
-    @FlakyTest(bugId = 149070587)
     @Test
     public void testLaunchSingleSecondaryHomeActivityOnDisplayWithDecorations() {
         createManagedHomeActivitySession(SINGLE_SECONDARY_HOME_ACTIVITY);
@@ -340,7 +338,6 @@
      * Tests launching a multi-instance home activity on virtual display with system decoration
      * support.
      */
-    @FlakyTest(bugId = 149070587)
     @Test
     public void testLaunchHomeActivityOnDisplayWithDecorations() {
         createManagedHomeActivitySession(HOME_ACTIVITY);
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index e5a6f05..cd054c2 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -101,6 +101,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import static java.lang.Integer.toHexString;
 
@@ -529,9 +530,18 @@
     }
 
     protected ComponentName getDefaultSecondaryHomeComponent() {
+        assumeTrue(supportsMultiDisplay());
         int resId = Resources.getSystem().getIdentifier(
-                "config_secondaryHomeComponent", "string", "android");
-        return ComponentName.unflattenFromString(mContext.getResources().getString(resId));
+                "config_secondaryHomePackage", "string", "android");
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_SECONDARY_HOME);
+        intent.setPackage(mContext.getResources().getString(resId));
+        final ResolveInfo resolveInfo =
+                mContext.getPackageManager().resolveActivity(intent, MATCH_DEFAULT_ONLY);
+        assertNotNull("Should have default secondary home activity", resolveInfo);
+
+        return new ComponentName(resolveInfo.activityInfo.packageName,
+                resolveInfo.activityInfo.name);
     }
 
     /**
diff --git a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
index ab44335..afae17e 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
@@ -22,12 +22,15 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.app.UiModeManager;
+import android.content.res.Configuration;
 import android.os.PowerManager;
 
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.BatteryUtils;
+import com.android.compatibility.common.util.SettingsUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.Test;
@@ -91,4 +94,57 @@
             assertFalse(manager.isPowerSaveMode());
         });
     }
+
+    /** Tests that Battery Saver exemptions activate when car mode is active. */
+    @Test
+    public void testCarModeExceptions() throws Exception {
+        UiModeManager uiModeManager = getContext().getSystemService(UiModeManager.class);
+        uiModeManager.disableCarMode(0);
+
+        final PowerManager powerManager = BatteryUtils.getPowerManager();
+
+        try {
+            runDumpsysBatteryUnplug();
+
+            SettingsUtils.set(SettingsUtils.NAMESPACE_GLOBAL, "battery_saver_constants",
+                    "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
+                    + ",enable_night_mode=true");
+
+            enableBatterySaver(true);
+
+            // Allow time for UI change.
+            Thread.sleep(1000);
+            assertTrue(powerManager.isPowerSaveMode());
+            assertEquals(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
+                    powerManager.getLocationPowerSaveMode());
+            assertEquals(Configuration.UI_MODE_NIGHT_YES,
+                    getContext().getResources().getConfiguration().uiMode
+                        & Configuration.UI_MODE_NIGHT_MASK);
+
+            uiModeManager.enableCarMode(0);
+            // Allow time for UI change.
+            Thread.sleep(1000);
+
+            final int locationPowerSaveMode = powerManager.getLocationPowerSaveMode();
+            assertTrue("Location power save mode didn't change from " + locationPowerSaveMode,
+                    locationPowerSaveMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY
+                            || locationPowerSaveMode == PowerManager.LOCATION_MODE_NO_CHANGE);
+            assertEquals(Configuration.UI_MODE_NIGHT_NO,
+                getContext().getResources().getConfiguration().uiMode
+                    & Configuration.UI_MODE_NIGHT_MASK);
+
+            uiModeManager.disableCarMode(0);
+            // Allow time for UI change.
+            Thread.sleep(1000);
+
+            assertEquals(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
+                powerManager.getLocationPowerSaveMode());
+            assertEquals(Configuration.UI_MODE_NIGHT_YES,
+                getContext().getResources().getConfiguration().uiMode
+                    & Configuration.UI_MODE_NIGHT_MASK);
+        } finally {
+            uiModeManager.disableCarMode(0);
+            SettingsUtils.delete(SettingsUtils.NAMESPACE_GLOBAL, "battery_saver_constants");
+        }
+    }
 }
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index 583ff7c..1a27bf0 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -26,7 +26,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
@@ -215,4 +217,62 @@
                 PARTIALLY_DIRECT_BOOT_AWARE_PACKAGE_NAME, 0);
         assertTrue(applicationInfo.isEncryptionAware());
     }
+
+    @Test
+    public void testWriteToParcelDontSquash() throws Exception {
+        // Make sure ApplicationInfo.writeToParcel() doesn't do the "squashing",
+        // because Parcel.allowSquashing() isn't called.
+
+        mApplicationInfo = getContext().getPackageManager().getApplicationInfo(mPackageName, 0);
+
+        final Parcel p = Parcel.obtain();
+        mApplicationInfo.writeToParcel(p, 0);
+        mApplicationInfo.writeToParcel(p, 0);
+
+        // Don't call Parcel.allowSquashing()
+
+        p.setDataPosition(0);
+        final ApplicationInfo copy1 = ApplicationInfo.CREATOR.createFromParcel(p);
+        final ApplicationInfo copy2 = ApplicationInfo.CREATOR.createFromParcel(p);
+
+        p.recycle();
+
+        assertNotSame(mApplicationInfo, copy1);
+
+        // writeToParcel() doesn't do the squashing, so copy1 and copy2 will be different.
+        assertNotSame(copy1, copy2);
+
+        // Check several fields to make sure they're properly copied.
+        assertEquals(mApplicationInfo.packageName, copy2.packageName);
+        assertEquals(copy1.packageName, copy2.packageName);
+
+        assertEquals(mApplicationInfo.flags, copy2.flags);
+        assertEquals(copy1.flags, copy2.flags);
+    }
+
+    @Test
+    public void testWriteToParcelSquash() throws Exception {
+        // Make sure ApplicationInfo.writeToParcel() does the "squashing", after
+        // Parcel.allowSquashing() is called.
+
+        mApplicationInfo = getContext().getPackageManager().getApplicationInfo(mPackageName, 0);
+
+        final Parcel p = Parcel.obtain();
+
+        final boolean prevSquashing = p.allowSquashing(); // Allow squashing.
+
+        mApplicationInfo.writeToParcel(p, 0);
+        mApplicationInfo.writeToParcel(p, 0);
+
+        p.setDataPosition(0);
+        final ApplicationInfo copy1 = ApplicationInfo.CREATOR.createFromParcel(p);
+        final ApplicationInfo copy2 = ApplicationInfo.CREATOR.createFromParcel(p);
+
+        p.recycle();
+
+        assertNotSame(mApplicationInfo, copy1);
+        assertSame(copy1, copy2); //
+
+        p.restoreAllowSquashing(prevSquashing);
+    }
 }
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java b/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
index b2aae0d..8cfab20 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
@@ -18,6 +18,7 @@
 
 
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageItemInfo;
@@ -63,6 +64,19 @@
         p.recycle();
     }
 
+    public void testApplicationInfoSame() {
+        ApplicationInfo ai = mPackageInfo.applicationInfo;
+
+        // Make sure all the components in it has the same ApplicationInfo.
+        for (ComponentInfo[] ar : new ComponentInfo[][]{
+                mPackageInfo.activities, mPackageInfo.services, mPackageInfo.providers,
+                mPackageInfo.receivers}) {
+            for (ComponentInfo ci : ar) {
+                assertSame("component=" + ci.getComponentName(), ai, ci.applicationInfo);
+            }
+        }
+    }
+
     private void checkPkgInfoSame(PackageInfo expected, PackageInfo actual) {
         assertEquals(expected.packageName, actual.packageName);
         assertEquals(expected.getLongVersionCode(), actual.getLongVersionCode());
diff --git a/tests/tests/content/src/android/content/pm/cts/ProviderInfoListTest.java b/tests/tests/content/src/android/content/pm/cts/ProviderInfoListTest.java
new file mode 100644
index 0000000..2578058
--- /dev/null
+++ b/tests/tests/content/src/android/content/pm/cts/ProviderInfoListTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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.content.pm.cts;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ProviderInfoList;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ProviderInfoListTest extends AndroidTestCase {
+    private static final String PACKAGE_NAME = "android.content.cts";
+
+    public void testApplicationInfoSquashed() throws Exception {
+        final PackageManager pm = getContext().getPackageManager();
+        final PackageInfo pi = pm.getPackageInfo(PACKAGE_NAME,
+                PackageManager.GET_PROVIDERS | PackageManager.GET_UNINSTALLED_PACKAGES);
+
+        // Make sure the package contains more than 1 providers.
+        assertNotNull(pi);
+        assertNotNull(pi.providers);
+        assertTrue(pi.providers.length > 1);
+
+        final List<ProviderInfo> providers = new ArrayList<>();
+        Collections.addAll(providers, pi.providers);
+
+        // Create a target list.
+        final ProviderInfoList source = ProviderInfoList.fromList(providers);
+
+        // Parcel it and uparcel
+        final Parcel p = Parcel.obtain();
+        source.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        final ProviderInfoList dest = ProviderInfoList.CREATOR.createFromParcel(p);
+        p.recycle();
+
+        final List<ProviderInfo> destList = dest.getList();
+        assertEquals(source.getList().size(), destList.size());
+        for (int i = 0; i < destList.size(); i++) {
+            assertEquals(destList.get(0).applicationInfo, destList.get(i).applicationInfo);
+        }
+    }
+}
diff --git a/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
index 44a9cc2..d5361d7 100644
--- a/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
+++ b/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
@@ -163,7 +163,7 @@
 
         // Analyze results
         assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures + ", ITERATIONS="
-                        + NUM_OF_RTT_ITERATIONS,
+                        + NUM_OF_RTT_ITERATIONS + ", AP RSSI=" + testAp.level,
                 numFailures <= NUM_OF_RTT_ITERATIONS * MAX_FAILURE_RATE_PERCENT / 100);
         if (numFailures != NUM_OF_RTT_ITERATIONS) {
             double distanceAvg = distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures);
diff --git a/tests/tests/provider/OWNERS b/tests/tests/provider/OWNERS
index fea932d..ed13f6fa 100644
--- a/tests/tests/provider/OWNERS
+++ b/tests/tests/provider/OWNERS
@@ -5,3 +5,5 @@
 tgunn@google.com
 nicksauer@google.com
 nona@google.com
+nandana@google.com
+zezeozue@google.com
diff --git a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
index f1829f6..31ffdd8 100644
--- a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
+++ b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
@@ -50,6 +50,14 @@
                 <data android:scheme="tel" />
             </intent-filter>
         </activity>
+        <service
+            android:name=".DialerInCallService"
+            android:permission="android.permission.BIND_INCALL_SERVICE">
+            <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
+            <intent-filter>
+                <action android:name="android.telecom.InCallService" />
+            </intent-filter>
+        </service>
 
         <!-- Sms -->
         <activity android:name=".SmsSendToActivity">
@@ -64,7 +72,6 @@
             android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
             <intent-filter>
                 <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
-                <category android:name="android.intent.category.DEFAULT" />
                 <data android:scheme="smsto" />
             </intent-filter>
         </service>
diff --git a/tests/tests/role/CtsRoleTestApp28/AndroidManifest.xml b/tests/tests/role/CtsRoleTestApp28/AndroidManifest.xml
index 8fd7012..574f768 100644
--- a/tests/tests/role/CtsRoleTestApp28/AndroidManifest.xml
+++ b/tests/tests/role/CtsRoleTestApp28/AndroidManifest.xml
@@ -45,6 +45,14 @@
                 <data android:scheme="tel" />
             </intent-filter>
         </activity>
+        <service
+            android:name=".DialerInCallService"
+            android:permission="android.permission.BIND_INCALL_SERVICE">
+            <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
+            <intent-filter>
+                <action android:name="android.telecom.InCallService" />
+            </intent-filter>
+        </service>
 
         <!-- Sms -->
         <activity android:name=".SmsSendToActivity">
@@ -59,7 +67,6 @@
             android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
             <intent-filter>
                 <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
-                <category android:name="android.intent.category.DEFAULT" />
                 <data android:scheme="smsto" />
             </intent-filter>
         </service>