Merge "Remove volume change test for default route" into oreo-cts-dev
diff --git a/apps/CameraITS/tests/scene1/scene1_0.67_scaled.pdf b/apps/CameraITS/tests/scene1/scene1_0.67_scaled.pdf
new file mode 100644
index 0000000..3103cd8
--- /dev/null
+++ b/apps/CameraITS/tests/scene1/scene1_0.67_scaled.pdf
Binary files differ
diff --git a/apps/CameraITS/tests/scene2/scene2_0.67_scaled.pdf b/apps/CameraITS/tests/scene2/scene2_0.67_scaled.pdf
new file mode 100644
index 0000000..7b64817
--- /dev/null
+++ b/apps/CameraITS/tests/scene2/scene2_0.67_scaled.pdf
Binary files differ
diff --git a/apps/CameraITS/tests/scene3/scene3_0.67_scaled.pdf b/apps/CameraITS/tests/scene3/scene3_0.67_scaled.pdf
new file mode 100644
index 0000000..a3e18e2
--- /dev/null
+++ b/apps/CameraITS/tests/scene3/scene3_0.67_scaled.pdf
Binary files differ
diff --git a/apps/CameraITS/tests/scene4/scene4_0.67_scaled.pdf b/apps/CameraITS/tests/scene4/scene4_0.67_scaled.pdf
new file mode 100644
index 0000000..7fb1e42
--- /dev/null
+++ b/apps/CameraITS/tests/scene4/scene4_0.67_scaled.pdf
Binary files differ
diff --git a/apps/CameraITS/tools/load_scene.py b/apps/CameraITS/tools/load_scene.py
index 4e245f4..6255137 100644
--- a/apps/CameraITS/tools/load_scene.py
+++ b/apps/CameraITS/tools/load_scene.py
@@ -17,17 +17,20 @@
 import subprocess
 import sys
 import time
-
+import numpy as np
 
 def main():
     """Load charts on device and display."""
-    camera_id = -1
     scene = None
     for s in sys.argv[1:]:
         if s[:6] == 'scene=' and len(s) > 6:
             scene = s[6:]
         elif s[:7] == 'screen=' and len(s) > 7:
             screen_id = s[7:]
+        elif s[:5] == 'dist=' and len(s) > 5:
+            chart_distance = float(re.sub('cm', '', s[5:]))
+        elif s[:4] == 'fov=' and len(s) > 4:
+            camera_fov = float(s[4:])
 
     cmd = ('adb -s %s shell am force-stop com.google.android.apps.docs' %
            screen_id)
@@ -43,8 +46,13 @@
 
     remote_scene_file = '/sdcard/Download/%s.pdf' % scene
     local_scene_file = os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests',
-                                    scene, scene+'.pdf')
-    print 'Loading %s on %s' % (remote_scene_file, screen_id)
+                                    scene)
+    if np.isclose(chart_distance, 22, rtol=0.1) and camera_fov < 90:
+        local_scene_file = os.path.join(local_scene_file,
+                                        scene+'_0.67_scaled.pdf')
+    else:
+        local_scene_file = os.path.join(local_scene_file, scene+'.pdf')
+    print 'Loading %s on %s' % (local_scene_file, screen_id)
     cmd = 'adb -s %s push %s /mnt%s' % (screen_id, local_scene_file,
                                         remote_scene_file)
     subprocess.Popen(cmd.split())
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index de269b7..dedc969 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -13,8 +13,10 @@
 # limitations under the License.
 
 import copy
+import math
 import os
 import os.path
+import re
 import tempfile
 import subprocess
 import time
@@ -25,9 +27,25 @@
 from its.device import ItsSession
 
 CHART_DELAY = 1  # seconds
+CHART_DISTANCE = 30.0  # cm
 FACING_EXTERNAL = 2
 SKIP_RET_CODE = 101  # note this must be same as tests/scene*/test_*
 
+def calc_camera_fov():
+    """Determine the camera field of view from internal params."""
+    with ItsSession() as cam:
+        props = cam.get_camera_properties()
+    try:
+        focal_l = props['android.lens.info.availableFocalLengths'][0]
+        sensor_size = props['android.sensor.info.physicalSize']
+        diag = math.sqrt(sensor_size['height'] ** 2 +
+                         sensor_size['width'] ** 2)
+        fov = str(round(2 * math.degrees(math.atan(diag / (2 * focal_l))), 2))
+    except ValueError:
+        fov = str(0)
+    print 'Calculated FoV: %s' % fov
+    return fov
+
 
 def skip_sensor_fusion():
     """Determine if sensor fusion test is skipped for this camera."""
@@ -60,6 +78,7 @@
                all android devices.
         skip_scene_validation: force skip scene validation. Used when test scene
                  is setup up front and don't require tester validation.
+        dist:    [Experimental] chart distance in cm.
     """
 
     # Not yet mandated tests
@@ -120,6 +139,7 @@
     rot_rig_id = None
 
     skip_scene_validation = False
+    chart_distance = CHART_DISTANCE
 
     for s in sys.argv[1:]:
         if s[:7] == "camera=" and len(s) > 7:
@@ -135,6 +155,8 @@
             # The default '$VID:$PID:$CH' is '04d8:fc73:1'
         elif s == 'skip_scene_validation':
             skip_scene_validation = True
+        elif s[:5] == 'dist=' and len(s) > 5:
+            chart_distance = float(re.sub('cm', '', s[5:]))
 
     auto_scene_switch = chart_host_id is not None
     merge_result_switch = result_device_id is not None
@@ -163,7 +185,7 @@
                     break
 
         if not valid_scenes:
-            print "Unknown scene specifiied:", s
+            print 'Unknown scene specified:', s
             assert False
         scenes = temp_scenes
 
@@ -225,6 +247,7 @@
             assert wake_code == 0
 
     for camera_id in camera_ids:
+        camera_fov = calc_camera_fov()
         # Loop capturing images until user confirm test scene is correct
         camera_id_arg = "camera=" + camera_id
         print "Preparing to run ITS on camera", camera_id
@@ -260,9 +283,11 @@
                     if (not merge_result_switch or
                             (merge_result_switch and camera_ids[0] == '0')):
                         scene_arg = 'scene=' + scene
+                        chart_dist_arg = 'dist= ' + str(chart_distance)
+                        fov_arg = 'fov=' + camera_fov
                         cmd = ['python',
                                os.path.join(os.getcwd(), 'tools/load_scene.py'),
-                               scene_arg, screen_id_arg]
+                               scene_arg, chart_dist_arg, fov_arg, screen_id_arg]
                     else:
                         time.sleep(CHART_DELAY)
                 else:
diff --git a/apps/CtsVerifier/res/values-vrheadset/strings.xml b/apps/CtsVerifier/res/values-vrheadset/strings.xml
index 3132dfd..750ef34 100644
--- a/apps/CtsVerifier/res/values-vrheadset/strings.xml
+++ b/apps/CtsVerifier/res/values-vrheadset/strings.xml
@@ -24,4 +24,151 @@
         <item>com.android.cts.verifier.notifications.ShortcutThrottlingResetActivity</item>
         <item>com.android.cts.verifier.vr.VrListenerVerifierActivity</item>
     </string-array>
+
+    <!-- Override default strings for features that non-handheld devices may not support. -->
+
+    <!-- This specific test is disabling tethering, non-handheld devices may not support tethering and this may effectively be a no-op. -->
+    <string name="disallow_config_tethering_action">
+        Configuring tethering and portable hotspots.\n
+        NOTE: If the device does not support tethering please pass the test using the green check mark.\n
+    </string>
+
+    <!-- This specific test is disallowing usb file transfers. non-handheld devices may not support usb file transfer features and this may effectively be a no-op. -->
+    <string name="device_owner_disallow_usb_file_transfer_test_info">
+            Please press below button to set the \"disallow USB file transfer\" restriction.\n
+            If a USB notification appears, open the notification and check that the
+            \"Transfer files (MTP)\" and \"Transfer photos (PTP)\" cannot be selected and trigger a
+            support message when trying to select them.\n
+            NOTE: If the device does not support MTP or PTP please pass the test using the green check mark.\n
+            Check if you can mount the device as a USB drive on your desktop computer. The test is
+            successful if you cannot mount the device, and files from your phone cannot be
+            downloaded through USB.\n
+            Please mark the test accordingly.
+    </string>
+
+    <!-- This specific test is disabling the keyguard, non-handheld devices may not support keyguard and this may effectively be a no-op. -->
+    <string name="device_owner_disable_keyguard_test_info">
+        NOTE: If the device does not support keyguard please pass the test using the green check mark.\n
+        Before running this test, please make sure you have not set any device lockscreen password.\n
+        Please press the below button to disable the keyguard. Press the power button on your device to
+        switch off the screen. Then press the power button to switch the screen back on and verify that
+        no keyguard was shown.\n
+        Next, press the button to reenable the keyguard and repeat the above steps, this time verifying that
+        a keyguard was shown.\n
+        Please mark the test accordingly.
+    </string>
+
+    <!-- This specific test is disabling the status bar, non-handheld devices may not support a status bar and this may effectively be a no-op. -->
+    <string name="device_owner_disable_statusbar_test_info">
+        NOTE: If the device does not support a status bar, please pass the test using the green check mark. \n
+        Please press the below button to disable the status bar and verify that quick settings, notifications
+        and the assist gesture are no longer available.\n
+        Next, press the button to reenable the status bar and verify that quick settings, notification
+        and the assist gesture are available again.\n
+        Please mark the test accordingly.
+    </string>
+
+    <!-- This specific test is disabling keyguard/lock screen notifications, non-handheld devices may not support
+    keyguard/lock screen notifciations and this may effectively be a no-op. -->
+    <string name="disallow_keyguard_unredacted_notifications_set_step">
+        NOTE: If the device does not support a keyguard or lock screen notifications, please pass the test
+        using the green checkmark.\n
+        Disallow unredacted notifications when device is locked by turning on the switch below
+    </string>
+
+    <!-- This specific test is disabling trust agents, non-handheld devices may not support trust agents and this may effectively be a no-op. -->
+    <string name="provisioning_byod_disable_trust_agents_instruction">
+        NOTE: If the device does not support trust agents, please mark the test as \"Pass\".\n
+        Please press the Go button to go to Settings > Security. Then go to Trusted agents and\n
+        check if the agents are shown as disabled by the administrator.
+        Then please press Back and mark the test as \"Pass\" or \"Fail\".
+    </string>
+
+     <!-- This specific test is disabling keyguard notifications, non-handheld devices may not support keyguard and this may effectively be a no-op. -->
+    <string name="device_admin_disable_notifications_instruction">
+        NOTE: If the device does not support a keyguard, please mark the test as \"Pass\".\n
+        Please press the Go button to lock the screen. Wait a few seconds to see
+        if a notification appears. Expected result is no notifications appear.
+        You should be able to see one after unlocking.
+    </string>
+
+    <!-- This specific test is disabling keyguard notifications, non-handheld devices may not support keyguard and this may effectively be a no-op. -->
+    <string name="device_admin_disable_unredacted_notifications_instruction">
+        Note: If the device does not support a keyguard, please mark the test as \"Pass"\.\n
+        Please press the Go button to lock the screen. Wait a few seconds to see
+        if a notification appears. Expected result is a notification appear with
+        its content hidden. You should be able to see the content after unlocking.
+    </string>
+
+    <!-- This specific test is setting a lock screen message, non-handheld devices may not support lock scren messages
+    and this may effectively be a no-op. -->
+    <string name="lock_screen_info_set_step">
+        NOTE: If the device does not support lock screen messages, pass the test using the green checkmark. \n
+        Select a lock screen info by setting a non-empty message in the edittext below.
+    </string>
+
+    <!-- This specific test is setting permitted accessibilty features, non-handheld devices may not support accessibility features and this may effectively be a no-op. -->
+    <string name="permitted_accessibility_services_set_step">
+        NOTE: If the device does not support accessibility features, please pass the test using the green check mark.\n
+        Check that \'Dummy Accessibility service\' is not enabled in Settings and disallow \'Dummy Accessibility service\' from permitted accessibility services by turning on
+        the switch below.
+    </string>
+
+    <!-- This specific test is disabling volume changes via audio settings.
+    Non-handheld devices may not support an audio settings page and this may effectively be a no-op. -->
+    <string name="disallow_adjust_volume_action">
+        NOTE: If the device does not support an audio settings page, please pass the test using the green checkmark.\n
+        Adjusting the volume
+    </string>
+
+    <!-- Non-handheld devices may not support a keyguard and this test may effectively be a no-op. -->
+    <string name="enterprise_privacy_keyguard_info">
+        NOTE: If the device does not support a keyguard, please pass the test using the green checkmark.\n
+        Please do the following:\n
+        1) Press the Go button to open Settings.\n
+        2) Navigate to \"Security\" &gt; \"Screen lock\" and select the first screen lock type that is not \"None\".\n
+        3) Use the Back button to return to this page.\n
+        4) Lock the device.\n
+        5) Verify that on the lock screen, you are not told the device is managed.\n
+        6) Unlock the device.\n
+        7) Repeat steps (1) through (6) for each screen lock type other than \"None\".
+    </string>
+
+    <!-- Non-handheld devices may not support quicksettings and this test may effectively be a no-op. -->
+    <string name="enterprise_privacy_quick_settings_info">
+        NOTE: If the device does not support quick settings, please pass the test using the green check mark. \n
+        Please do the following:\n
+        1) Press the Clear Org button.\n
+        2) Open and fully expand Quick Settings.\n
+        3) Verify that at the bottom of Quick Settings, you are told the device is managed.\n
+        4) Close Quick Settings.\n
+        5) Press the Set Org button.\n
+        6) Open and fully expand Quick Settings.\n
+        7) Verify that at the bottom of Quick Settings, you are told the device is managed by \"Foo, Inc.\".\n
+        8) Tap on the information.\n
+        9) Verify that a dialog informing you about device monitoring opens.\n
+        10) Tap the \"Learn more\" link.\n
+        11) Verify that a screen informing you what your managing organization can do is shown.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+
+    <!-- Non-handheld devices may not support quicksettings but still should be able to validate the API via
+    the notification section. -->
+    <string name="device_owner_network_logging_ui_info">
+        Please do the following:\n
+        NOTE: If the device does not support quick settings, please only check the notifications section.\n
+        1) Open and fully expand Quick Settings.\n
+        2) Check that you are told that your device is managed.\n
+        3) Close Quick Settings.\n
+        4) Enable network logging by tapping on the left button below.\n
+        5) Open Quick Settings again. Check that an icon appeared next to the text about device management.\n
+        6) Verify that a notification including the same icon popped up, informing you that network logging has been enabled.\n
+        7) Tap the notification.\n
+        8) Verify that a dialog about device monitoring opens, and informs you about: the name of the app that manages this device, details about the device owner\'s capabilities, and information that the admin has activated network logging and can see all network traffic.\n
+        9) Close the dialog.\n
+        10) Tap the right button below to disable network logging.\n
+        11) Verify that the notification disappeared.\n
+    </string>
+
 </resources>
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
index 5ef3a93..5b3339b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
@@ -139,8 +139,11 @@
         int numTests = countTestCases();
         long startTime = System.currentTimeMillis();
         listener.testRunStarted(getClass().getName(), numTests);
-        super.run(new HostTestListener(listener));
-        listener.testRunEnded(System.currentTimeMillis() - startTime, Collections.emptyMap());
+        try {
+            super.run(new HostTestListener(listener));
+        } finally {
+            listener.testRunEnded(System.currentTimeMillis() - startTime, Collections.emptyMap());
+        }
     }
 
     /**
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
index e092888..12e9698 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
@@ -42,7 +42,7 @@
         if (mDpm.isAdminActive(cn)) {
             mDpm.removeActiveAdmin(cn);
             // Wait until device admin is not active (with 2 minutes timeout).
-            for (int i = 0; i < 2 * 60 && mDpm.isAdminActive(cn); i++) {
+            for (int i = 0; i < 5 * 60 && mDpm.isAdminActive(cn); i++) {
                 Thread.sleep(1000);  // 1 second.
             }
         }
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 9cbf328..c8e327e 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -1285,7 +1285,6 @@
 
         executeShellCommand("am start -n " + getActivityComponentName(LAUNCHING_ACTIVITY));
         final int stackId = mVrHeadset ? defaultDisplayFrontStackId : frontStackId;
-        final int focusedStackTaskCount = mVrHeadset ? 3 : 1;
         mAmWmState.waitForFocusedStack(mDevice, stackId);
 
         // Check that the third intent is redirected to the first task
@@ -1294,8 +1293,10 @@
         assertEquals("Activity launched on default display must be resumed",
                 getActivityComponentName(LAUNCHING_ACTIVITY), secondFrontStack.mResumedActivity);
         mAmWmState.assertFocusedStack("Focus must be on primary display", stackId);
-        assertEquals("Focused stack must contain correct tasks",
-                focusedStackTaskCount, secondFrontStack.getTasks().size());
+        if (!mVrHeadset) {
+            assertEquals("Focused stack must contain correct tasks",
+                1, secondFrontStack.getTasks().size());
+        }
         assertEquals("Focused task must only contain 1 activity",
                 1, secondFrontStack.getTasks().get(0).mActivities.size());
     }
@@ -1357,9 +1358,10 @@
         assertEquals("Activity must be launched on secondary display",
                 getActivityComponentName(LAUNCHING_ACTIVITY),
                 secondFrontStack.mResumedActivity);
-        final int taskCount = mVrHeadset ? 3 : 2;
-        assertEquals("Secondary display must contain correct tasks",
-                taskCount, secondFrontStack.getTasks().size());
+        if (!mVrHeadset) {
+            assertEquals("Secondary display must contain correct tasks",
+                2, secondFrontStack.getTasks().size());
+        }
     }
 
     /**
diff --git a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
index 74ead54..945bebd 100755
--- a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
+++ b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
@@ -41,7 +41,7 @@
     private static final int GRAY = 0xFF808080;
 
     /** Maximum allowable number of consecutive failed pixels. */
-    private static final int MAX_CONSECUTIVE_FAILURES = 1;
+    private static final int MAX_CONSECUTIVE_FAILURES = 2;
 
     private final String mName;
     private final File mExpected;
@@ -87,6 +87,43 @@
         return (color & 0xFF000000) >>> 24;
     }
 
+    /**
+     * Verifies that the pixels of reference and generated images are similar
+     * within a specified threshold.
+     *
+     * @param expected expected image
+     * @param actual actual image
+     * @param threshold maximum difference per channel
+     * @return {@code true} if the images are similar, false otherwise
+     */
+    private static boolean checkNeighbors(int x, int y, BufferedImage reference,
+            BufferedImage generated, int threshold) {
+        final int w = generated.getWidth();
+        final int h = generated.getHeight();
+        for (int i = x - MAX_CONSECUTIVE_FAILURES; i <= x + MAX_CONSECUTIVE_FAILURES; i++) {
+            if (i >= 0 && i != x && i < w) {
+                for (int j = y - MAX_CONSECUTIVE_FAILURES; j <= y + MAX_CONSECUTIVE_FAILURES; j++) {
+                    if (j >= 0 && j != y && j < h) {
+                        final int p1 = reference.getRGB(i, j);
+                        final int p2 = generated.getRGB(i, j);
+
+                        final int dr = getAlphaScaledRed(p1) - getAlphaScaledRed(p2);
+                        final int dg = getAlphaScaledGreen(p1) - getAlphaScaledGreen(p2);
+                        final int db = getAlphaScaledBlue(p1) - getAlphaScaledBlue(p2);
+
+                        if (Math.abs(db) <= threshold &&
+                            Math.abs(dg) <= threshold &&
+                            Math.abs(dr) <= threshold) {
+                            // If we find at least one matching neighbor, we assume the difference
+                            // is in antialiasing.
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
 
     /**
      * Verifies that the pixels of reference and generated images are similar
@@ -107,7 +144,6 @@
 
         double maxDist = 0;
         for (int i = 0; i < w; i++) {
-            int consecutive = 0;
 
             for (int j = 0; j < h; j++) {
                 final int p1 = reference.getRGB(i, j);
@@ -121,45 +157,16 @@
                     Math.abs(dg) > threshold ||
                     Math.abs(dr) > threshold) {
                     System.err.println("fail dr=" + dr+ " dg=" + dg+ " db=" + db);
-
-                    consecutive++;
-
-                    if (consecutive > MAX_CONSECUTIVE_FAILURES) {
+                    if (!checkNeighbors(i, j, reference, generated, threshold)) {
                         System.err.println("consecutive fail");
                         return false;
                     }
-                } else {
-                    consecutive = 0;
                 }
             }
         }
         return true;
     }
 
-    /**
-     * Returns the perceptual difference score (lower is better) for the
-     * provided ARGB pixels.
-     */
-    private static double computeLabDistance(int p1, int p2) {
-        // Blend with neutral gray to account for opacity.
-        p1 = ColorUtils.blendSrcOver(p1, GRAY);
-        p2 = ColorUtils.blendSrcOver(p2, GRAY);
-
-        // Convert to LAB.
-        double[] lab1 = new double[3];
-        double[] lab2 = new double[3];
-        ColorUtils.colorToLAB(p1, lab1);
-        ColorUtils.colorToLAB(p2, lab2);
-
-        // Compute the distance
-        double dist = 0;
-        for (int i = 0; i < 3; i++) {
-            double delta = lab1[i] - lab2[i];
-            dist += delta * delta;
-        }
-        return Math.sqrt(dist);
-    }
-
     private static void createDiff(BufferedImage expected, BufferedImage actual, File out)
             throws IOException {
         final int w1 = expected.getWidth();
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 08f0754..9303955 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -66,6 +66,10 @@
         <activity android:name=".OutOfProcessLoginActivity"
             android:process="android.autofillservice.cts.outside"/>
         <activity android:name=".FragmentContainerActivity" />
+        <activity android:name=".WebViewActivity"/>
+        <activity android:name=".TrampolineWelcomeActivity"/>
+        <activity android:name=".AttachedContextActivity"/>
+        <activity android:name=".TrampolineForResultActivity" />
 
         <service
             android:name=".InstrumentedAutoFillService"
@@ -75,6 +79,22 @@
                 <action android:name="android.service.autofill.AutofillService" />
             </intent-filter>
         </service>
+        <service
+            android:name=".NoOpAutofillService"
+            android:label="NoOpAutofillService"
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE" >
+            <intent-filter>
+                <action android:name="android.service.autofill.AutofillService" />
+            </intent-filter>
+        </service>
+        <!--  BadAutofillService does not declare the proper permission -->
+        <service
+            android:name=".BadAutofillService"
+            android:label="BadAutofillService">
+            <intent-filter>
+                <action android:name="android.service.autofill.AutofillService" />
+            </intent-filter>
+        </service>
     </application>
 
     <instrumentation
diff --git a/tests/autofillservice/src/android/autofillservice/cts/BadAutofillService.java b/tests/autofillservice/src/android/autofillservice/cts/BadAutofillService.java
new file mode 100644
index 0000000..19a8ec1
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/BadAutofillService.java
@@ -0,0 +1,49 @@
+/*
+ * 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.CancellationSignal;
+import android.service.autofill.AutofillService;
+import android.service.autofill.FillCallback;
+import android.service.autofill.FillRequest;
+import android.service.autofill.SaveCallback;
+import android.service.autofill.SaveRequest;
+import android.util.Log;
+
+/**
+ * An {@link AutofillService} implementation that does fails if called upon.
+ */
+public class BadAutofillService extends AutofillService {
+
+    private static final String TAG = "BadAutofillService";
+
+    static final String SERVICE_NAME = BadAutofillService.class.getPackage().getName()
+            + "/." + BadAutofillService.class.getSimpleName();
+    static final String SERVICE_LABEL = "BadAutofillService";
+
+    @Override
+    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
+            FillCallback callback) {
+        Log.e(TAG, "onFillRequest() should never be called");
+        throw new UnsupportedOperationException("onFillRequest() should never be called");
+    }
+
+    @Override
+    public void onSaveRequest(SaveRequest request, SaveCallback callback) {
+        Log.e(TAG, "onSaveRequest() should never be called");
+        throw new UnsupportedOperationException("onSaveRequest() should never be called");
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 0280b44..0c384ff 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -59,6 +59,8 @@
 
     static final boolean VERBOSE = false;
 
+    static final String MY_PACKAGE = "android.autofillservice.cts";
+
     static final String ID_USERNAME_LABEL = "username_label";
     static final String ID_USERNAME = "username";
     static final String ID_PASSWORD_LABEL = "password_label";
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
index 9650fff..0840f28 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
@@ -53,8 +53,11 @@
  */
 public class InstrumentedAutoFillService extends AutofillService {
 
-    static final String SERVICE_NAME = InstrumentedAutoFillService.class.getPackage()
-            .getName() + "/." + InstrumentedAutoFillService.class.getSimpleName();
+    static final String SERVICE_PACKAGE = Helper.MY_PACKAGE;
+    static final String SERVICE_CLASS = "InstrumentedAutoFillService";
+
+    static final String SERVICE_NAME = SERVICE_PACKAGE + "/." + SERVICE_CLASS;
+    protected static final String sServiceLabel = SERVICE_CLASS;
 
     private static final String TAG = "InstrumentedAutoFillService";
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/NoOpAutofillService.java b/tests/autofillservice/src/android/autofillservice/cts/NoOpAutofillService.java
new file mode 100644
index 0000000..a4c2a10
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/NoOpAutofillService.java
@@ -0,0 +1,42 @@
+/*
+ * 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.CancellationSignal;
+import android.service.autofill.AutofillService;
+import android.service.autofill.FillCallback;
+import android.service.autofill.FillRequest;
+import android.service.autofill.SaveCallback;
+import android.service.autofill.SaveRequest;
+
+/**
+ * {@link AutofillService} implementation that does not do anything...
+ */
+public class NoOpAutofillService extends AutofillService {
+
+    static final String SERVICE_NAME = NoOpAutofillService.class.getPackage().getName()
+            + "/." + NoOpAutofillService.class.getSimpleName();
+    static final String SERVICE_LABEL = "NoOpAutofillService";
+
+    @Override
+    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
+            FillCallback callback) {
+    }
+
+    @Override
+    public void onSaveRequest(SaveRequest request, SaveCallback callback) {
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java b/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
new file mode 100644
index 0000000..c91fd13
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.autofillservice.cts;
+
+import static android.autofillservice.cts.Helper.runShellCommand;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.Settings;
+import android.support.test.uiautomator.UiObject2;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class SettingsIntentTest extends AutoFillServiceTestCase {
+
+    private static final int MY_REQUEST_CODE = 42;
+
+    @Rule
+    public final AutofillActivityTestRule<TrampolineForResultActivity> mActivityRule =
+            new AutofillActivityTestRule<TrampolineForResultActivity>(
+                    TrampolineForResultActivity.class);
+
+    protected TrampolineForResultActivity mActivity;
+
+    @Before
+    public void setActivity() {
+        mActivity = mActivityRule.getActivity();
+    }
+
+    @After
+    public void killSettings() {
+        // Make sure there's no Settings activity left , as it could fail future tests.
+        runShellCommand("am force-stop com.android.settings");
+    }
+
+    @Test
+    public void testMultipleServicesShown() throws Exception {
+        disableService();
+
+        // Launches Settings.
+        mActivity.startForResult(newSettingsIntent(), MY_REQUEST_CODE);
+
+        // Asserts services are shown.
+        sUiBot.assertShownByText(InstrumentedAutoFillService.sServiceLabel);
+        sUiBot.assertShownByText(NoOpAutofillService.SERVICE_LABEL);
+        sUiBot.assertNotShowingForSure(BadAutofillService.SERVICE_LABEL);
+
+        // Finishes and asserts result.
+        sUiBot.pressBack();
+        mActivity.assertResult(Activity.RESULT_CANCELED);
+    }
+
+    @Test
+    public void testWarningShown_userRejectsByTappingBack() throws Exception {
+        disableService();
+
+        // Launches Settings.
+        mActivity.startForResult(newSettingsIntent(), MY_REQUEST_CODE);
+
+        // Asserts services are shown.
+        final UiObject2 object = sUiBot
+                .assertShownByText(InstrumentedAutoFillService.sServiceLabel);
+        object.click();
+
+        // TODO(b/79615759): should assert that "autofill_confirmation_message" is shown, but that
+        // string belongs to Settings - we need to move it to frameworks/base first (and/or use
+        // a resource id, also on framework).
+        // So, for now, just asserts the service name is showing again (in the popup), and the other
+        // services are not showing (because the popup hides then).
+
+        final UiObject2 msgObj = sUiBot.assertShownById("android:id/message");
+        final String msg = msgObj.getText();
+        assertWithMessage("Wrong warning message").that(msg)
+                .contains(InstrumentedAutoFillService.sServiceLabel);
+
+        // NOTE: assertion below is fine because it looks for the full text, not a substring
+        sUiBot.assertNotShowingForSure(InstrumentedAutoFillService.sServiceLabel);
+        sUiBot.assertNotShowingForSure(NoOpAutofillService.SERVICE_LABEL);
+        sUiBot.assertNotShowingForSure(BadAutofillService.SERVICE_LABEL);
+
+        // Finishes and asserts result.
+        sUiBot.pressBack();
+        mActivity.assertResult(Activity.RESULT_CANCELED);
+    }
+
+    // TODO(b/79615759): add testWarningShown_userRejectsByTappingCancel() and
+    // testWarningShown_userAccepts() - these tests would require adding the strings and resource
+    // ids to frameworks/base
+
+    private Intent newSettingsIntent() {
+        return new Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                .setData(Uri.parse("package:" + Helper.MY_PACKAGE));
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TrampolineForResultActivity.java b/tests/autofillservice/src/android/autofillservice/cts/TrampolineForResultActivity.java
new file mode 100644
index 0000000..6cdd33e
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/TrampolineForResultActivity.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.Intent;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Activity used to launch another activity for result.
+ */
+// TODO: move to common code
+public class TrampolineForResultActivity extends AbstractAutoFillActivity {
+    private static final String TAG = "TrampolineForResultActivity";
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+
+    private int mExpectedRequestCode;
+    private int mActualRequestCode;
+    private int mActualResultCode;
+
+    /**
+     * Starts an activity for result.
+     */
+    public void startForResult(Intent intent, int requestCode) {
+        mExpectedRequestCode = requestCode;
+        startActivityForResult(intent, requestCode);
+    }
+
+    /**
+     * Asserts the activity launched by {@link #startForResult(Intent, int)} was finished with the
+     * expected result code, or fails if it times out.
+     */
+    public void assertResult(int expectedResultCode) throws Exception {
+        final boolean called = mLatch.await(1000, TimeUnit.MILLISECONDS);
+        assertWithMessage("Result not received in 1s").that(called).isTrue();
+        assertWithMessage("Wrong actual code").that(mActualRequestCode)
+            .isEqualTo(mExpectedRequestCode);
+        assertWithMessage("Wrong result code").that(mActualResultCode)
+                .isEqualTo(expectedResultCode);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        Log.d(TAG, "onActivityResult(): req=" + requestCode + ", res=" + resultCode);
+        mActualRequestCode = requestCode;
+        mActualResultCode = resultCode;
+        mLatch.countDown();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 495b05c..774d7fe 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -177,8 +177,34 @@
      * {@link #assertDatasets(String...)}.
      */
     public UiObject2 assertShownByText(String text) {
-        final UiObject2 object = waitForObject(By.text(text));
-        assertWithMessage(text).that(object).isNotNull();
+        return assertShownByText(text, UI_TIMEOUT_MS);
+    }
+
+    public UiObject2 assertShownByText(String text, int timeoutMs) {
+        final UiObject2 object = waitForObject(By.text(text), timeoutMs);
+        assertWithMessage("No node with text '%s'", text).that(object).isNotNull();
+        return object;
+    }
+
+    /**
+     * Asserts that the text is not showing for sure in the screen "as is", i.e., without waiting
+     * for it.
+     *
+     * <p>Typically called after another assertion that waits for a condition to be shown.
+     */
+    public void assertNotShowingForSure(String text) throws Exception {
+        final UiObject2 object = mDevice.findObject(By.text(text));
+        assertWithMessage("Find node with text '%s'", text).that(object).isNull();
+    }
+
+    /**
+     * Asserts a node with the given content description is shown.
+     *
+     */
+    public UiObject2 assertShownByContentDescription(String contentDescription) {
+        final UiObject2 object = waitForObject(By.desc(contentDescription));
+        assertWithMessage("No node with content description '%s'", contentDescription).that(object)
+                .isNotNull();
         return object;
     }
 
@@ -204,8 +230,10 @@
     /**
      * Asserts the id is shown on the screen.
      */
-    void assertShownById(String id) {
-        assertThat(waitForObject(By.res(id))).isNotNull();
+    UiObject2 assertShownById(String id) throws Exception {
+        final UiObject2 object = waitForObject(By.res(id));
+        assertThat(object).isNotNull();
+        return object;
     }
 
     /**
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index d2da516..378e39c 100755
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -89,8 +89,8 @@
     }
 
     public void testAssistStructure() throws Throwable {
-        if (mActivityManager.isLowRamDevice()) {
-            Log.d(TAG, "Not running assist tests on low-RAM device.");
+        if (!mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS)) {
+            Log.d(TAG, "Not running assist tests - voice_recognizers feature is not supported");
             return;
         }
         mTestActivity.start3pApp(TEST_CASE_TYPE);
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 33a7758..461f5d0 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -48,6 +48,7 @@
 public class AssistTestBase extends ActivityInstrumentationTestCase2<TestStartActivity> {
     private static final String TAG = "AssistTestBase";
 
+    protected static final String FEATURE_VOICE_RECOGNIZERS = "android.software.voice_recognizers";
     protected ActivityManager mActivityManager;
     protected TestStartActivity mTestActivity;
     protected AssistContent mAssistContent;
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index 3c5a0fb..20437eb 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -49,8 +49,8 @@
     }
 
     public void testContextAndScreenshotOff() throws Exception {
-        if (mActivityManager.isLowRamDevice()) {
-            Log.d(TAG, "Not running assist tests on low-RAM device.");
+        if (!mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS)) {
+            Log.d(TAG, "Not running assist tests - voice_recognizers feature is not supported");
             return;
         }
         // Both settings off
diff --git a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
index fc7c8fb3..43364f8 100644
--- a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
@@ -77,8 +77,8 @@
     }
 
     public void testSecureActivity() throws Exception {
-        if (mActivityManager.isLowRamDevice()) {
-            Log.d(TAG, "Not running assist tests on low-RAM device.");
+        if (!mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS)) {
+            Log.d(TAG, "Not running assist tests - voice_recognizers feature is not supported");
             return;
         }
         mTestActivity.startTest(TEST_CASE_TYPE);
diff --git a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
index 237fe6e..a4a1606 100644
--- a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
+++ b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
@@ -121,8 +121,8 @@
     }
 
     public void testLayerDoesNotTriggerLifecycleMethods() throws Exception {
-        if (mActivityManager.isLowRamDevice()) {
-            Log.d(TAG, "Not running assist tests on low-RAM device.");
+        if (!mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS)) {
+            Log.d(TAG, "Not running assist tests - voice_recognizers feature is not supported");
             return;
         }
         mTestActivity.startTest(Utils.LIFECYCLE);
diff --git a/tests/tests/content/src/android/content/cts/ContentProviderCursorWindowTest.java b/tests/tests/content/src/android/content/cts/ContentProviderCursorWindowTest.java
index e771461..5cfd532 100644
--- a/tests/tests/content/src/android/content/cts/ContentProviderCursorWindowTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentProviderCursorWindowTest.java
@@ -17,14 +17,13 @@
 package android.content.cts;
 
 import android.database.Cursor;
+import android.database.CursorWindowAllocationException;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.platform.test.annotations.SecurityTest;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import java.io.IOException;
-
 /**
  * Test {@link CursorWindowContentProvider} .
  */
@@ -32,11 +31,20 @@
 public class ContentProviderCursorWindowTest extends AndroidTestCase {
     private static final String TAG = "ContentProviderCursorWindowTest";
 
-    public void testQuery() throws IOException {
-        Cursor cursor = getContext().getContentResolver().query(
-                Uri.parse("content://cursorwindow.provider/hello"),
-                null, null, null, null
-        );
+    public void testQuery() {
+        // First check if the system has a patch for enforcing protected Parcel data
+        Cursor cursor;
+        try {
+            cursor = getContext().getContentResolver().query(
+                    Uri.parse("content://cursorwindow.provider/hello"),
+                    null, null, null, null);
+        } catch (CursorWindowAllocationException expected) {
+            Log.i(TAG, "Expected exception: " + expected);
+            return;
+        }
+
+        // If the system has no patch for protected Parcel data,
+        // it should still fail while reading from the cursor
         try {
             cursor.moveToFirst();
 
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 34e8a82..60394be 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -1375,7 +1375,19 @@
         }
 
         // start decoding
-        final long kTimeOutUs = 5000;
+        MediaFormat outFormat = codec.getOutputFormat();
+        long kTimeOutUs = 5000; // 5ms timeout
+        String outMime = format.getString(MediaFormat.KEY_MIME);
+        if (outMime != null && outMime.startsWith("video/")) {
+            int outWidth = outFormat.getInteger(MediaFormat.KEY_WIDTH);
+            int outHeight = outFormat.getInteger(MediaFormat.KEY_HEIGHT);
+            // in the 4K decoding case in byte buffer mode, set kTimeOutUs to 10ms as decode may
+            // involve a memcpy
+            if (outWidth * outHeight >= 8000000) {
+                kTimeOutUs = 10000;
+            }
+        }
+
         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
         boolean sawInputEOS = false;
         boolean sawOutputEOS = false;
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index 81c8caf..e38d210 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_PACKAGE_NAME := CtsDeviceInfo
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 
 include $(BUILD_CTS_DEVICE_INFO_PACKAGE)