Merge "Bypass JvmtiHostTest at bridged architecture" into oc-dev
diff --git a/hostsidetests/media/bitstreams/Android.mk b/hostsidetests/media/bitstreams/Android.mk
index b07309c..6a0cafe 100644
--- a/hostsidetests/media/bitstreams/Android.mk
+++ b/hostsidetests/media/bitstreams/Android.mk
@@ -30,6 +30,8 @@
 
 LOCAL_SDK_VERSION := current
 
+LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/DynamicConfig.xml
+
 include $(BUILD_HOST_JAVA_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java b/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
index d7965b7..92f0d2a 100644
--- a/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
+++ b/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
@@ -62,11 +62,6 @@
 
     private static final String KEY_SIZE = "size";
     private static final String UTF_8 = "utf-8";
-    private static final String DYNAMIC_CONFIG = "dynamicConfig";
-    private static final String DYNAMIC_CONFIG_ENTRY = "entry";
-    private static final String DYNAMIC_CONFIG_KEY = "key";
-    private static final String DYNAMIC_CONFIG_VALUE = "value";
-
     /** Instrumentation status code used to write resolution to metrics */
     private static final int INST_STATUS_IN_PROGRESS = 2;
 
@@ -104,14 +99,14 @@
             XmlSerializer formats = Xml.newSerializer();
             formats.setOutput(out, UTF_8);
             formats.startDocument(UTF_8, true);
-            formats.startTag(null, DYNAMIC_CONFIG);
+            formats.startTag(null, MediaBitstreams.DYNAMIC_CONFIG);
 
             DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(MediaBitstreams.K_MODULE);
             for (String path : config.keySet()) {
 
-                formats.startTag(null, DYNAMIC_CONFIG_ENTRY);
-                formats.attribute(null, DYNAMIC_CONFIG_KEY, path);
-                formats.startTag(null, DYNAMIC_CONFIG_VALUE);
+                formats.startTag(null, MediaBitstreams.DYNAMIC_CONFIG_ENTRY);
+                formats.attribute(null, MediaBitstreams.DYNAMIC_CONFIG_KEY, path);
+                formats.startTag(null, MediaBitstreams.DYNAMIC_CONFIG_VALUE);
 
                 String formatStr = config.getValue(path);
                 if (formatStr != null && !formatStr.isEmpty()) {
@@ -133,12 +128,12 @@
                     formats.text(formatStringBuilder.toString());
                 }
 
-                formats.endTag(null, DYNAMIC_CONFIG_VALUE);
-                formats.endTag(null, DYNAMIC_CONFIG_ENTRY);
+                formats.endTag(null, MediaBitstreams.DYNAMIC_CONFIG_VALUE);
+                formats.endTag(null, MediaBitstreams.DYNAMIC_CONFIG_ENTRY);
 
             }
 
-            formats.endTag(null, DYNAMIC_CONFIG);
+            formats.endTag(null, MediaBitstreams.DYNAMIC_CONFIG);
             formats.endDocument();
 
         }
diff --git a/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java b/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java
index 2266254..8b9a507 100644
--- a/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java
+++ b/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java
@@ -50,6 +50,12 @@
     public static final String K_TEST_GET_SUPPORTED_BITSTREAMS = "testGetSupportedBitstreams";
     public static final String K_NATIVE_CRASH = "native crash";
 
+    public static final String DYNAMIC_CONFIG_XML = "DynamicConfig.xml";
+    public static final String DYNAMIC_CONFIG = "dynamicConfig";
+    public static final String DYNAMIC_CONFIG_ENTRY = "entry";
+    public static final String DYNAMIC_CONFIG_KEY = "key";
+    public static final String DYNAMIC_CONFIG_VALUE = "value";
+
     /* utilities */
     /**
      * @param bitstreamPath path of individual bitstream relative to bitstreams root,
@@ -73,5 +79,4 @@
         return String.format("%s:%s", path, name);
     }
 
-
 }
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4ClassRunnerWithParameters.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4ClassRunnerWithParameters.java
new file mode 100644
index 0000000..4b4a2a7
--- /dev/null
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4ClassRunnerWithParameters.java
@@ -0,0 +1,126 @@
+/*
+ * 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.media.cts.bitstreams;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.TestClass;
+import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters;
+import org.junit.runners.parameterized.ParametersRunnerFactory;
+import org.junit.runners.parameterized.TestWithParameters;
+
+/**
+ * Custom JUnit4 parameterized test runner that also accommodate {@link IDeviceTest}.
+ */
+public class DeviceJUnit4ClassRunnerWithParameters extends BlockJUnit4ClassRunnerWithParameters
+        implements IDeviceTest, IBuildReceiver, IAbiReceiver {
+
+    private ITestDevice mDevice;
+    private IBuildInfo mBuildInfo;
+    private IAbi mAbi;
+    private Collection<FrameworkMethod> mFilteredChildren;
+    private Object mChildrenLock = new Object();
+
+    public DeviceJUnit4ClassRunnerWithParameters(TestWithParameters test) throws InitializationError {
+        super(test);
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuildInfo = buildInfo;
+    }
+
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    @Override
+    public Description getDescription() {
+        Description description = Description.createSuiteDescription(getTestClass().getJavaClass());
+        for (FrameworkMethod child : getFilteredChildren()) {
+            description.addChild(describeChild(child));
+        }
+        return description;
+    }
+
+    private Collection<FrameworkMethod> getFilteredChildren() {
+        if (mFilteredChildren == null) {
+            synchronized (mChildrenLock) {
+                if (mFilteredChildren == null) {
+                    mFilteredChildren = Collections.unmodifiableCollection(getChildren());
+                }
+            }
+        }
+        return mFilteredChildren;
+    }
+
+    /**
+     * We override createTest in order to set the device.
+     */
+    @Override
+    public Object createTest() throws Exception {
+        Object testObj = super.createTest();
+        if (testObj instanceof IDeviceTest) {
+            if (mDevice == null) {
+                throw new IllegalArgumentException("Missing device");
+            }
+            ((IDeviceTest) testObj).setDevice(mDevice);
+        }
+        if (testObj instanceof IBuildReceiver) {
+            if (mBuildInfo == null) {
+                throw new IllegalArgumentException("Missing build information");
+            }
+            ((IBuildReceiver) testObj).setBuild(mBuildInfo);
+        }
+        // We are more flexible about abi information since not always available.
+        if (testObj instanceof IAbiReceiver) {
+            ((IAbiReceiver) testObj).setAbi(mAbi);
+        }
+        return testObj;
+    }
+
+    public static class RunnerFactory implements ParametersRunnerFactory {
+        @Override
+        public Runner createRunnerForTestWithParameters(TestWithParameters test)
+                throws InitializationError {
+            return new DeviceJUnit4ClassRunnerWithParameters(test);
+        }
+    }
+
+}
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4Parameterized.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4Parameterized.java
new file mode 100644
index 0000000..5c0b7bc
--- /dev/null
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4Parameterized.java
@@ -0,0 +1,80 @@
+/*
+ * 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.media.cts.bitstreams;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import java.util.List;
+import org.junit.runner.Runner;
+import org.junit.runners.Parameterized;
+
+/**
+ * Custom JUnit4 parameterized test runner that also accommodate {@link IDeviceTest}.
+ */
+public class DeviceJUnit4Parameterized extends Parameterized
+        implements IDeviceTest, IBuildReceiver, IAbiReceiver {
+
+    private ITestDevice mDevice;
+    private List<Runner> mRunners;
+
+    public DeviceJUnit4Parameterized(Class<?> klass) throws Throwable {
+        super(klass);
+        mRunners = super.getChildren();
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        for (Runner runner : mRunners) {
+            if (runner instanceof IBuildReceiver) {
+                ((IBuildReceiver)runner).setBuild(buildInfo);
+            }
+        }
+    }
+
+    @Override
+    public void setAbi(IAbi abi) {
+        for (Runner runner : mRunners) {
+            if (runner instanceof IAbiReceiver) {
+                ((IAbiReceiver)runner).setAbi(abi);
+            }
+        }
+    }
+
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+        for (Runner runner : mRunners) {
+            if (runner instanceof IDeviceTest) {
+                ((IDeviceTest)runner).setDevice(device);
+            }
+        }
+    }
+
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+
+    @Override
+    protected List<Runner> getChildren() {
+        return mRunners;
+    }
+}
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java
index 5f5e4cd..a016575 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java
@@ -25,7 +25,6 @@
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
@@ -34,25 +33,35 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.nio.file.Files;
 import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
 
 /**
  * Test that verifies video bitstreams decode pixel perfectly
  */
 @OptionClass(alias="media-bitstreams-test")
-@RunWith(DeviceJUnit4ClassRunner.class)
+@RunWith(DeviceJUnit4Parameterized.class)
+@UseParametersRunnerFactory(DeviceJUnit4ClassRunnerWithParameters.RunnerFactory.class)
 public class MediaBitstreamsTest implements IDeviceTest, IBuildReceiver, IAbiReceiver {
 
     @Option(name = MediaBitstreams.OPT_HOST_BITSTEAMS_PATH,
@@ -93,12 +102,34 @@
     private IAbi mAbi;
     private ITestDevice mDevice;
 
-    private MediaBitstreamsTest(String prefix) {
-        mPrefix = prefix;
+    @Parameters(name = "{0}")
+    public static Iterable<? extends Object> bitstreams() {
+        final String dynConfXml = new File("/", MediaBitstreams.DYNAMIC_CONFIG_XML).toString();
+        try (InputStream is = MediaBitstreamsTest.class.getResourceAsStream(dynConfXml)) {
+            List<String> entries = new ArrayList<>();
+            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+            parser.setInput(is, null);
+            parser.nextTag();
+            parser.require(XmlPullParser.START_TAG, null, MediaBitstreams.DYNAMIC_CONFIG);
+            while (parser.next() != XmlPullParser.END_DOCUMENT) {
+                if (parser.getEventType() != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                String name = parser.getName();
+                if (name.equals(MediaBitstreams.DYNAMIC_CONFIG_ENTRY)) {
+                    final String key = MediaBitstreams.DYNAMIC_CONFIG_KEY;
+                    entries.add(parser.getAttributeValue(null, key));
+                }
+            }
+            return entries;
+        } catch (XmlPullParserException | IOException e) {
+            CLog.e(e);
+            return Collections.emptyList();
+        }
     }
 
-    public MediaBitstreamsTest() {
-        this("");
+    public MediaBitstreamsTest(String prefix) {
+        mPrefix = prefix;
     }
 
     @Override
@@ -320,312 +351,6 @@
     }
 
     @Test
-    public void testH264Yuv420_8bitBpBitrate() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/bitrate");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpLevels() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/levels");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpParamsCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/params/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpParamsCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/params/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpParamsCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/params/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpParamsCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/params/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpParamsCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/params/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpResolutions() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/resolutions");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpSlicesCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/slices/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpSlicesCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/slices/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpSlicesCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/slices/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpSlicesCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/slices/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitBpSlicesCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/bp/slices/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpBitrate() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/bitrate");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpGopCrowd_640x360p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/gop/crowd_640x360p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpGopCrowd_854x480p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/gop/crowd_854x480p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpGopCrowd_1280x720p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/gop/crowd_1280x720p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpGopCrowd_1920x1080p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/gop/crowd_1920x1080p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpGopCrowd_3840x2160p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/gop/crowd_3840x2160p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpLevels() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/levels");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpParamsCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/params/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpParamsCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/params/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpParamsCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/params/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpParamsCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/params/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpParamsCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/params/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpResolutions() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/resolutions");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpSlicesCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/slices/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpSlicesCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/slices/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpSlicesCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/slices/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpSlicesCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/slices/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitMpSlicesCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/mp/slices/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpBitrate() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/bitrate");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpGopCrowd_640x360p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/gop/crowd_640x360p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpGopCrowd_854x480p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/gop/crowd_854x480p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpGopCrowd_1280x720p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/gop/crowd_1280x720p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpGopCrowd_1920x1080p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/gop/crowd_1920x1080p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpGopCrowd_3840x2160p50() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/gop/crowd_3840x2160p50");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpLevels() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/levels");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpParamsCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/params/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpParamsCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/params/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpParamsCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/params/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpParamsCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/params/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpParamsCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/params/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpResolutions() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/resolutions");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpScalingmatrixCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/scalingmatrix/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpScalingmatrixCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/scalingmatrix/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpScalingmatrixCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/scalingmatrix/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpScalingmatrixCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/scalingmatrix/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpScalingmatrixCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/scalingmatrix/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpSlicesCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/slices/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpSlicesCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/slices/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpSlicesCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/slices/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpSlicesCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/slices/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testH264Yuv420_8bitHpSlicesCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("h264/yuv420/8bit/hp/slices/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testVp8Yuv420_8bitBitrate() throws Exception {
-        testBitstreamsConformance("vp8/yuv420/8bit/bitrate");
-    }
-
-    @Test
-    public void testVp8Yuv420_8bitParamsCrowd_640x360p50f32() throws Exception {
-        testBitstreamsConformance("vp8/yuv420/8bit/params/crowd_640x360p50f32");
-    }
-
-    @Test
-    public void testVp8Yuv420_8bitParamsCrowd_854x480p50f32() throws Exception {
-        testBitstreamsConformance("vp8/yuv420/8bit/params/crowd_854x480p50f32");
-    }
-
-    @Test
-    public void testVp8Yuv420_8bitParamsCrowd_1280x720p50f32() throws Exception {
-        testBitstreamsConformance("vp8/yuv420/8bit/params/crowd_1280x720p50f32");
-    }
-
-    @Test
-    public void testVp8Yuv420_8bitParamsCrowd_1920x1080p50f32() throws Exception {
-        testBitstreamsConformance("vp8/yuv420/8bit/params/crowd_1920x1080p50f32");
-    }
-
-    @Test
-    public void testVp8Yuv420_8bitParamsCrowd_3840x2160p50f32() throws Exception {
-        testBitstreamsConformance("vp8/yuv420/8bit/params/crowd_3840x2160p50f32");
-    }
-
-    @Test
-    public void testVp8Yuv420_8bitResolution() throws Exception {
-        testBitstreamsConformance("vp8/yuv420/8bit/resolution");
-    }
-
-    @Ignore
-    @Test
     public void testBitstreamsConformance()
             throws DeviceNotAvailableException, IOException {
         testBitstreamsConformance(mPrefix);
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 4e07eb4..57347ff 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -451,6 +451,82 @@
     }
 
     /**
+     * Tests launching a non-resizeable activity on virtual display from activity there. It should
+     * land on the secondary display based on the resizeability of the root activity of the task.
+     */
+    public void testLaunchNonResizeableActivityFromSecondaryDisplaySameTask() throws Exception {
+        if (!supportsMultiDisplay()) { return; }
+
+        // Create new virtual display.
+        final DisplayState newDisplay = new VirtualDisplayBuilder(this).build();
+
+        // Launch activity on new secondary display.
+        launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId);
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                LAUNCHING_ACTIVITY);
+
+        // Check that launching activity is on the secondary display.
+        int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        ActivityManagerState.ActivityStack frontStack =
+                mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be on the secondary display and resumed",
+                getActivityComponentName(LAUNCHING_ACTIVITY),
+                frontStack.mResumedActivity);
+        mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId);
+
+        // Launch non-resizeable activity from secondary display.
+        getLaunchActivityBuilder().setTargetActivityName(NON_RESIZEABLE_ACTIVITY_NAME).execute();
+
+        // Check that non-resizeable activity is on the secondary display, because of the resizeable
+        // root of the task.
+        frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        frontStack = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be on the primary display and resumed",
+                getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME),
+                frontStack.mResumedActivity);
+        mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId);
+    }
+
+    /**
+     * Tests launching a non-resizeable activity on virtual display from activity there. It should
+     * land on some different suitable display (usually - on the default one).
+     */
+    public void testLaunchNonResizeableActivityFromSecondaryDisplayNewTask() throws Exception {
+        if (!supportsMultiDisplay()) { return; }
+
+        // Create new virtual display.
+        final DisplayState newDisplay = new VirtualDisplayBuilder(this).build();
+
+        // Launch activity on new secondary display.
+        launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId);
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                LAUNCHING_ACTIVITY);
+
+        // Check that launching activity is on the secondary display.
+        int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        ActivityManagerState.ActivityStack frontStack =
+                mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be on the secondary display and resumed",
+                getActivityComponentName(LAUNCHING_ACTIVITY),
+                frontStack.mResumedActivity);
+        mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId);
+
+        // Launch non-resizeable activity from secondary display.
+        getLaunchActivityBuilder().setTargetActivityName(NON_RESIZEABLE_ACTIVITY_NAME)
+                .setNewTask(true).setMultipleTask(true).execute();
+
+        // Check that non-resizeable activity is on the primary display.
+        frontStackId = mAmWmState.getAmState().getFocusedStackId();
+        frontStack = mAmWmState.getAmState().getStackById(frontStackId);
+        assertFalse("Launched activity must be on a different display",
+                newDisplay.mDisplayId == frontStack.mDisplayId);
+        assertEquals("Launched activity must be resumed",
+                getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME),
+                frontStack.mResumedActivity);
+        mAmWmState.assertFocusedStack("Focus must be on a just launched activity", frontStackId);
+    }
+
+    /**
      * Tests launching an activity on virtual display and then launching another activity via shell
      * command and without specifying the display id - the second activity must appear on the
      * primary display.
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index eeea510..702709b 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -1127,6 +1127,7 @@
         private String mTargetPackage = componentName;
         private boolean mToSide;
         private boolean mRandomData;
+        private boolean mNewTask;
         private boolean mMultipleTask;
         private int mDisplayId = INVALID_DISPLAY_ID;
         private String mLaunchingActivityName = LAUNCHING_ACTIVITY;
@@ -1150,6 +1151,11 @@
             return this;
         }
 
+        public LaunchActivityBuilder setNewTask(boolean newTask) {
+            mNewTask = newTask;
+            return this;
+        }
+
         public LaunchActivityBuilder setMultipleTask(boolean multipleTask) {
             mMultipleTask = multipleTask;
             return this;
@@ -1198,6 +1204,9 @@
             if (mRandomData) {
                 commandBuilder.append(" --ez random_data true");
             }
+            if (mNewTask) {
+                commandBuilder.append(" --ez new_task true");
+            }
             if (mMultipleTask) {
                 commandBuilder.append(" --ez multiple_task true");
             }
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index cbf3e93..f667015 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -385,6 +385,7 @@
 
             wifiConfiguration = new WifiConfiguration();
             wifiConfiguration.SSID = SSID1;
+            wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
             int netId = mWifiManager.addNetwork(wifiConfiguration);
             assertTrue(existSSID(SSID1));
 
@@ -788,6 +789,11 @@
      * Note: Location mode must be enabled for this test.
      */
     public void testStartLocalOnlyHotspotSuccess() {
+        // first check that softap mode is supported by the device
+        if (!mWifiManager.isPortableHotspotSupported()) {
+            return;
+        }
+
         boolean wifiEnabled = mWifiManager.isWifiEnabled();
 
         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
@@ -808,6 +814,11 @@
      * Note: Location mode must be enabled for this test.
      */
     public void testSetWifiEnabledByAppDoesNotStopHotspot() {
+        // first check that softap mode is supported by the device
+        if (!mWifiManager.isPortableHotspotSupported()) {
+            return;
+        }
+
         boolean wifiEnabled = mWifiManager.isWifiEnabled();
 
         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
@@ -827,6 +838,11 @@
      * Note: Location mode must be enabled for this test.
      */
     public void testStartLocalOnlyHotspotSingleRequestByApps() {
+        // first check that softap mode is supported by the device
+        if (!mWifiManager.isPortableHotspotSupported()) {
+            return;
+        }
+
         boolean caughtException = false;
 
         boolean wifiEnabled = mWifiManager.isWifiEnabled();
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowTest.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowTest.java
index 03bbd32..731dbfb 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowTest.java
@@ -134,26 +134,22 @@
 
         assertInitialState();
 
-        // Workaround for some focus bug in the framework that would ruin screenshot test.
-        mTestUtils.tapOnViewWithText(mActivity.getTitle().toString());
-
         CharSequence title = mActivity.getTitle();
 
-        // Take screenshot
-        Bitmap before = mTestUtils.takeScreenshot();
-
         tapOnPrefs2Header();
         assertHeadersHidden();
 
         pressBack();
         assertHeadersShown();
 
+        // Verify that no headers are focused.
+        assertHeadersNotFocused();
+
         // Verify that the title was properly restored.
         assertEquals(title, mActivity.getTitle());
 
-        // Compare screenshots
-        Bitmap after = mTestUtils.takeScreenshot();
-        assertScreenshotsAreEqual(before, after);
+        // Verify that everthing restores back to initial state again.
+        assertInitialState();
     }
 
     void backPressToExitInner() {
@@ -317,14 +313,14 @@
                 false /* noHeaders */, INITIAL_TITLE_RES_ID);
 
         assertInitialStateForFragment();
-        String testTitle = mActivity.getResources().getString(INITIAL_TITLE_RES_ID);
 
         if (mIsMultiPane) {
+            String testTitle = mActivity.getResources().getString(INITIAL_TITLE_RES_ID);
             // Title should not be shown.
             assertTextHidden(testTitle);
         } else {
             // Title should be shown.
-            assertTextShown(testTitle);
+            assertTitleShown();
         }
     }
 
@@ -389,8 +385,7 @@
         assertPanelPrefs1Hidden();
         assertPanelPrefs2Shown();
 
-        String testTitle = mActivity.getResources().getString(INITIAL_TITLE_RES_ID);
-        assertTextShown(testTitle);
+        assertTitleShown();
     }
 
     /**
@@ -742,6 +737,11 @@
         assertTextShown(PREFS2_HEADER_TITLE);
     }
 
+    private void assertHeadersNotFocused() {
+        assertFalse(mTestUtils.isTextFocused(PREFS1_HEADER_TITLE));
+        assertFalse(mTestUtils.isTextFocused(PREFS2_HEADER_TITLE));
+    }
+
     private void assertHeadersHidden() {
         // We check '&' instead of each individual separately because these headers are also part
         // of individual preference panels breadcrumbs so it would fail for one.
@@ -781,6 +781,14 @@
         assertTrue(mTestUtils.isTextHidden(text));
     }
 
+    private void assertTitleShown() {
+        if (!mTestUtils.isOnWatchUiMode()) {
+            // On watch, activity title is not shown by default.
+            String testTitle = mActivity.getResources().getString(INITIAL_TITLE_RES_ID);
+            assertTextShown(testTitle);
+        }
+    }
+
     private void recreate() {
         runOnUiThread(() -> mActivity.recreate());
         SystemClock.sleep(1000);
diff --git a/tests/tests/preference2/src/android/preference2/cts/TestUtils.java b/tests/tests/preference2/src/android/preference2/cts/TestUtils.java
index 04e0ed9..6fdeff4 100644
--- a/tests/tests/preference2/src/android/preference2/cts/TestUtils.java
+++ b/tests/tests/preference2/src/android/preference2/cts/TestUtils.java
@@ -19,13 +19,16 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.UiAutomation;
+import android.app.UiModeManager;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
 import android.support.test.uiautomator.UiSelector;
 
 import com.android.compatibility.common.util.SystemUtil;
@@ -50,33 +53,63 @@
     }
 
     Bitmap takeScreenshot() {
+        // Only take screenshot once the screen is stable enough.
+        device.waitForIdle();
+
         Bitmap bt = mAutomation.takeScreenshot();
         // Crop-out the top bar where current time is displayed since any time change would
         // introduce flakiness (we are cutting 5% of the screen height).
         int yToCut = bt.getHeight() / 20;
-        // Crop the right side for scrollbar which might or might not be visible.
-        int xToCut = bt.getWidth() / 20;
+        // Crop the right side for scrollbar which might or might not be visible. But on
+        // watch, the scroll bar is a curve and occupies 20% of the screen on the right
+        // hand side.
+        int xToCut = isOnWatchUiMode() ? bt.getWidth() / 5 : bt.getWidth() / 20;
         bt = Bitmap.createBitmap(
                 bt, 0, yToCut, bt.getWidth() - xToCut, bt.getHeight() - yToCut);
+
         return bt;
     }
 
-    void tapOnViewWithText(String text) {
-        UiObject obj = device.findObject(new UiSelector().textMatches(text));
-        try {
-            obj.click();
-        } catch (UiObjectNotFoundException e) {
-            throw new AssertionError("View with text '" + text + "' was not found!", e);
+    void tapOnViewWithText(String searchText) {
+        if (searchText == null) {
+            return;
         }
-        device.waitForIdle();
+
+        try {
+          // If the current UI has shown text, just click on it.
+          UiObject text = new UiObject(new UiSelector().text(searchText));
+          if (text.exists() || text.waitForExists(1000)) {
+            text.click();
+            return;
+          }
+
+          // Otherwise, if it is scrollable, scroll to where the text is and tap.
+          UiScrollable textScroll =  new UiScrollable(new UiSelector().scrollable(true));
+
+          textScroll.scrollIntoView(new UiSelector().text(searchText));
+          text = new UiObject(new UiSelector().text(searchText));
+          text.click();
+        } catch (UiObjectNotFoundException e) {
+          throw new AssertionError("View with text '" + searchText + "' was not found!", e);
+        }
     }
 
-    boolean isTextShown(String text) {
-        UiObject obj = device.findObject(new UiSelector().textMatches(text));
-        if (obj.exists()) {
+    boolean isTextShown(String searchText) {
+        if (searchText == null) {
+            return false;
+        }
+
+        UiObject text = new UiObject(new UiSelector().text(searchText));
+        if (text.exists() || text.waitForExists(1000)) {
             return true;
         }
-        return obj.waitForExists(1000);
+
+        UiScrollable textScroll = new UiScrollable(new UiSelector().scrollable(true));
+        try {
+            return textScroll.scrollIntoView(new UiSelector().text(searchText));
+        } catch (UiObjectNotFoundException e) {
+            return false;
+        }
     }
 
     boolean isTextHidden(String text) {
@@ -87,6 +120,21 @@
         return obj.waitUntilGone(1000);
     }
 
+    boolean isTextFocused(String text) {
+        UiObject obj = device.findObject(new UiSelector().textMatches(text));
+        try {
+            return obj.isFocused();
+        } catch(UiObjectNotFoundException e) {
+            return false;
+        }
+    }
+
+    boolean isOnWatchUiMode() {
+        Context context = mInstrumentation.getTargetContext();
+        UiModeManager uiModeManager = context.getSystemService(UiModeManager.class);
+        return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_WATCH;
+    }
+
     void getMultiWindowFocus(Context context) {
         // Get window focus (otherwise back press would close multi-window instead of firing to the
         // Activity and also the automator would fail to find objects on the screen.
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerUsageTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerUsageTest.java
index 5018c3d..064ba58 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerUsageTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerUsageTest.java
@@ -102,35 +102,37 @@
             )));
         });
 
-        // Report usage.
-        final long start = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE;
-
-        runWithCaller(mPackageContext2, () -> getManager().reportShortcutUsed(id3));
-
-        final long end = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE;
-
-        // Check the log.
         final UsageStatsManager usm = getTestContext().getSystemService(UsageStatsManager.class);
 
-        // Note it's a bit silly, but because events are populated asynchronously,
-        // we need to wait until the last one is populated.
+        // Report usage.
+        final long start1 = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE;
+        runWithCaller(mPackageContext2, () -> getManager().reportShortcutUsed(id3));
+        final long end1 = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE;
 
-        retryUntil(() -> hasEvent(usm.queryEvents(start, end),
+        // Check the log.
+        retryUntil(() -> hasEvent(usm.queryEvents(start1, end1),
                 mPackageContext2.getPackageName(), id3), "Events weren't populated");
 
-        assertTrue(hasEvent(usm.queryEvents(start, end),
-                    mPackageContext2.getPackageName(), id3));
-
+        // Report usage.
+        final long start2 = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE;
         runWithCaller(mPackageContext1, () -> getManager().reportShortcutUsed(id1));
-        assertTrue(hasEvent(usm.queryEvents(start, end),
-                    mPackageContext1.getPackageName(), id1));
+        final long end2 = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE;
 
-        runWithCaller(mPackageContext1, () -> getManager().reportShortcutUsed(idManifest));
-        assertTrue(hasEvent(usm.queryEvents(start, end),
-                    mPackageContext1.getPackageName(), idManifest));
+        // Check the log.
+        retryUntil(() -> hasEvent(usm.queryEvents(start2, end2),
+                mPackageContext1.getPackageName(), id1), "Events weren't populated");
 
+        // Report usage.
+        final long start3 = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE;
         runWithCaller(mPackageContext1, () -> getManager().reportShortcutUsed(idNonexistance));
-        assertFalse(hasEvent(usm.queryEvents(start, end),
+        runWithCaller(mPackageContext1, () -> getManager().reportShortcutUsed(idManifest));
+        final long end3 = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE;
+
+        // Check the log.
+        retryUntil(() -> hasEvent(usm.queryEvents(start3, end3),
+                mPackageContext1.getPackageName(), idManifest), "Events weren't populated");
+        // Ensure that the nonexistent shortcut is not reported, even after the other one is.
+        assertFalse(hasEvent(usm.queryEvents(start3, end3),
                     mPackageContext1.getPackageName(), idNonexistance));
     }
 }