Squashed mnc-dev changes:

This contains all of the changes from b54aa51 to
791e51a on mnc-dev, except the changes
to tests/tests/security.

Bug: 24846656
Change-Id: I01f53a1a238ac49f86928e0e22796dc73e0e34af
diff --git a/CtsBuild.mk b/CtsBuild.mk
index c745885..ba158ce 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -40,6 +40,10 @@
 	$(foreach executable,$(1),$(CTS_TESTCASES_OUT)/$(executable))
 endef
 
+define cts-get-deqp-api-test-xmls
+	$(foreach file,$(call find-files-in-subdirs, external/deqp/android/cts/master, 'com.drawelements.deqp.$(1).*xml', .),$(CTS_TESTCASES_OUT)/$(file))
+endef
+
 define cts-get-deqp-test-xmls
-	$(foreach api,$(1),$(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(api).xml)
+	$(foreach api,$(1),$(call cts-get-deqp-api-test-xmls,$(api)))
 endef
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index cf7da2f..975ac47 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -100,6 +100,7 @@
     CtsManagedProfileApp \
     CtsMonkeyApp \
     CtsMonkeyApp2 \
+    CtsPackageInstallerApp \
     CtsPermissionApp \
     CtsSimpleApp \
     CtsSimplePreMApp \
@@ -193,6 +194,7 @@
     CtsSecurityTestCases \
     CtsSignatureTestCases \
     CtsSpeechTestCases \
+    CtsSystemUiTestCases \
     CtsTelecomTestCases \
     CtsTelecomTestCases2 \
     CtsTelephonyTestCases \
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index 756f959..835a4a4 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -448,8 +448,8 @@
 
         The out_surfaces field can specify the width(s), height(s), and
         format(s) of the captured image. The formats may be "yuv", "jpeg",
-        "dng", "raw", "raw10", or "raw12". The default is a YUV420 frame ("yuv")
-        corresponding to a full sensor frame.
+        "dng", "raw", "raw10", "raw12", or "rawStats". The default is a YUV420
+        frame ("yuv") corresponding to a full sensor frame.
 
         Note that one or more surfaces can be specified, allowing a capture to
         request images back in multiple formats (e.g.) raw+yuv, raw+jpeg,
@@ -536,6 +536,25 @@
             yuv_caps           = do_capture( [req1,req2], yuv_fmt           )
             yuv_caps, raw_caps = do_capture( [req1,req2], [yuv_fmt,raw_fmt] )
 
+        The "rawStats" format processes the raw image and returns a new image
+        of statistics from the raw image. The format takes additional keys,
+        "gridWidth" and "gridHeight" which are size of grid cells in a 2D grid
+        of the raw image. For each grid cell, the mean and variance of each raw
+        channel is computed, and the do_capture call returns two 4-element float
+        images of dimensions (rawWidth / gridWidth, rawHeight / gridHeight),
+        concatenated back-to-back, where the first iamge contains the 4-channel
+        means and the second contains the 4-channel variances.
+
+        For the rawStats format, if the gridWidth is not provided then the raw
+        image width is used as the default, and similarly for gridHeight. With
+        this, the following is an example of a output description that computes
+        the mean and variance across each image row:
+
+            {
+                "gridHeight": 1,
+                "format": "rawStats"
+            }
+
         Args:
             cap_request: The Python dict/list specifying the capture(s), which
                 will be converted to JSON and sent to the device.
@@ -550,7 +569,8 @@
             * data: the image data as a numpy array of bytes.
             * width: the width of the captured image.
             * height: the height of the captured image.
-            * format: image the format, in ["yuv","jpeg","raw","raw10","dng"].
+            * format: image the format, in [
+                        "yuv","jpeg","raw","raw10","raw12","rawStats","dng"].
             * metadata: the capture result object (Python dictionary).
         """
         cmd = {}
@@ -577,9 +597,13 @@
         nsurf = 1 if out_surfaces is None else len(cmd["outputSurfaces"])
         if len(formats) > len(set(formats)):
             raise its.error.Error('Duplicate format requested')
-        if "dng" in formats and "raw" in formats or \
-                "dng" in formats and "raw10" in formats or \
-                "raw" in formats and "raw10" in formats:
+        raw_formats = 0;
+        raw_formats += 1 if "dng" in formats else 0
+        raw_formats += 1 if "raw" in formats else 0
+        raw_formats += 1 if "raw10" in formats else 0
+        raw_formats += 1 if "raw12" in formats else 0
+        raw_formats += 1 if "rawStats" in formats else 0
+        if raw_formats > 1:
             raise its.error.Error('Different raw formats not supported')
 
         # Detect long exposure time and set timeout accordingly
@@ -603,14 +627,16 @@
         # the burst, however individual images of different formats can come
         # out in any order for that capture.
         nbufs = 0
-        bufs = {"yuv":[], "raw":[], "raw10":[], "dng":[], "jpeg":[]}
+        bufs = {"yuv":[], "raw":[], "raw10":[], "raw12":[],
+                "rawStats":[], "dng":[], "jpeg":[]}
         mds = []
         widths = None
         heights = None
         while nbufs < ncap*nsurf or len(mds) < ncap:
             jsonObj,buf = self.__read_response_from_socket()
             if jsonObj['tag'] in ['jpegImage', 'yuvImage', 'rawImage', \
-                    'raw10Image', 'dngImage'] and buf is not None:
+                    'raw10Image', 'raw12Image', 'rawStatsImage', 'dngImage'] \
+                    and buf is not None:
                 fmt = jsonObj['tag'][:-5]
                 bufs[fmt].append(buf)
                 nbufs += 1
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index ea01a3e..a5ac60b 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -81,6 +81,25 @@
     else:
         raise its.error.Error('Invalid format %s' % (cap["format"]))
 
+def unpack_rawstats_capture(cap):
+    """Unpack a rawStats capture to the mean and variance images.
+
+    Args:
+        cap: A capture object as returned by its.device.do_capture.
+
+    Returns:
+        Tuple (mean_image var_image) of float-4 images, with non-normalized
+        pixel values computed from the RAW16 images on the device
+    """
+    assert(cap["format"] == "rawStats")
+    w = cap["width"]
+    h = cap["height"]
+    img = numpy.ndarray(shape=(2*h*w*4,), dtype='<f', buffer=cap["data"])
+    analysis_image = img.reshape(2,h,w,4)
+    mean_image = analysis_image[0,:,:,:].reshape(h,w,4)
+    var_image = analysis_image[1,:,:,:].reshape(h,w,4)
+    return mean_image, var_image
+
 def unpack_raw10_capture(cap, props):
     """Unpack a raw-10 capture to a raw-16 capture.
 
@@ -604,6 +623,21 @@
         variances.append(numpy.var(img[:,:,i], dtype=numpy.float64))
     return variances
 
+def compute_image_snrs(img):
+    """Calculate the SNR (db) of each color channel in the image.
+
+    Args:
+        img: Numpy float image array, with pixel values in [0,1].
+
+    Returns:
+        A list of SNR value, one per color channel in the image.
+    """
+    means = compute_image_means(img)
+    variances = compute_image_variances(img)
+    std_devs = [math.sqrt(v) for v in variances]
+    snr = [20 * math.log10(m/s) for m,s in zip(means, std_devs)]
+    return snr
+
 def write_image(img, fname, apply_gamma=False):
     """Save a float-3 numpy array image to a file.
 
diff --git a/apps/CameraITS/pymodules/its/objects.py b/apps/CameraITS/pymodules/its/objects.py
index 82346ec..ac384fb 100644
--- a/apps/CameraITS/pymodules/its/objects.py
+++ b/apps/CameraITS/pymodules/its/objects.py
@@ -152,24 +152,37 @@
 
     return req
 
-def get_available_output_sizes(fmt, props):
+def get_available_output_sizes(fmt, props, max_size=None, match_ar_size=None):
     """Return a sorted list of available output sizes for a given format.
 
     Args:
         fmt: the output format, as a string in
             ["jpg", "yuv", "raw", "raw10", "raw12"].
         props: the object returned from its.device.get_camera_properties().
+        max_size: (Optional) A (w,h) tuple.
+            Sizes larger than max_size (either w or h)  will be discarded.
+        match_ar_size: (Optional) A (w,h) tuple.
+            Sizes not matching the aspect ratio of match_ar_size will be
+            discarded.
 
     Returns:
         A sorted list of (w,h) tuples (sorted large-to-small).
     """
-    fmt_codes = {"raw":0x20, "raw10":0x25, "raw12":0x26, "yuv":0x23,
+    AR_TOLERANCE = 0.03
+    fmt_codes = {"raw":0x20, "raw10":0x25, "raw12":0x26,"yuv":0x23,
                  "jpg":0x100, "jpeg":0x100}
     configs = props['android.scaler.streamConfigurationMap']\
                    ['availableStreamConfigurations']
     fmt_configs = [cfg for cfg in configs if cfg['format'] == fmt_codes[fmt]]
     out_configs = [cfg for cfg in fmt_configs if cfg['input'] == False]
     out_sizes = [(cfg['width'],cfg['height']) for cfg in out_configs]
+    if max_size:
+        out_sizes = [s for s in out_sizes if
+                s[0] <= max_size[0] and s[1] <= max_size[1]]
+    if match_ar_size:
+        ar = match_ar_size[0] / float(match_ar_size[1])
+        out_sizes = [s for s in out_sizes if
+                abs(ar - s[0] / float(s[1])) <= AR_TOLERANCE]
     out_sizes.sort(reverse=True)
     return out_sizes
 
diff --git a/apps/CameraITS/tests/inprog/test_rawstats.py b/apps/CameraITS/tests/inprog/test_rawstats.py
new file mode 100644
index 0000000..8083f0b
--- /dev/null
+++ b/apps/CameraITS/tests/inprog/test_rawstats.py
@@ -0,0 +1,48 @@
+# Copyright 2015 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.
+
+import its.image
+import its.caps
+import its.device
+import its.objects
+import its.target
+import os.path
+import math
+
+def main():
+    """Test capturing some rawstats data.
+    """
+    NAME = os.path.basename(__file__).split(".")[0]
+
+    with its.device.ItsSession() as cam:
+
+        cam.do_3a(do_af=False);
+        req = its.objects.auto_capture_request()
+
+        for (gw,gh) in [(16,16)]:#,(4080,1)]:
+            cap = cam.do_capture(req,
+                {"format":"rawStats","gridWidth":gw,"gridHeight":gh})
+            mean_image, var_image = its.image.unpack_rawstats_capture(cap)
+
+            if gw > 1 and gh > 1:
+                h,w,_ = mean_image.shape
+                for ch in range(4):
+                    m = mean_image[:,:,ch].reshape(h,w,1)/1023.0
+                    v = var_image[:,:,ch].reshape(h,w,1)
+                    its.image.write_image(m, "%s_mean_ch%d.jpg" % (NAME,ch), True)
+                    its.image.write_image(v, "%s_var_ch%d.jpg" % (NAME,ch), True)
+
+if __name__ == '__main__':
+    main()
+
diff --git a/apps/CameraITS/tests/scene1/test_exposure.py b/apps/CameraITS/tests/scene1/test_exposure.py
index 26c398d..89bc724 100644
--- a/apps/CameraITS/tests/scene1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1/test_exposure.py
@@ -35,8 +35,10 @@
     THRESHOLD_MAX_OUTLIER_DIFF = 0.1
     THRESHOLD_MIN_LEVEL = 0.1
     THRESHOLD_MAX_LEVEL = 0.9
-    THRESHOLD_MAX_LEVEL_DIFF = 0.025
+    THRESHOLD_MAX_LEVEL_DIFF = 0.03
     THRESHOLD_MAX_LEVEL_DIFF_WIDE_RANGE = 0.05
+    THRESHOLD_ROUND_DOWN_GAIN = 0.1
+    THRESHOLD_ROUND_DOWN_EXP = 0.05
 
     mults = []
     r_means = []
@@ -50,21 +52,33 @@
                              its.caps.per_frame_control(props))
 
         e,s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
+        s_e_product = s*e
         expt_range = props['android.sensor.info.exposureTimeRange']
         sens_range = props['android.sensor.info.sensitivityRange']
 
-        m = 1
+        m = 1.0
         while s*m < sens_range[1] and e/m > expt_range[0]:
             mults.append(m)
-            req = its.objects.manual_capture_request(s*m, e/m)
+            s_test = round(s*m)
+            e_test = s_e_product / s_test
+            print "Testsing s:", s_test, "e:", e_test
+            req = its.objects.manual_capture_request(s_test, e_test)
             cap = cam.do_capture(req)
+            s_res = cap["metadata"]["android.sensor.sensitivity"]
+            e_res = cap["metadata"]["android.sensor.exposureTime"]
+            assert(0 <= s_test - s_res < s_test * THRESHOLD_ROUND_DOWN_GAIN)
+            assert(0 <= e_test - e_res < e_test * THRESHOLD_ROUND_DOWN_EXP)
+            s_e_product_res = s_res * e_res
+            request_result_ratio = s_e_product / s_e_product_res
+            print "Capture result s:", s_test, "e:", e_test
             img = its.image.convert_capture_to_rgb_image(cap)
             its.image.write_image(img, "%s_mult=%3.2f.jpg" % (NAME, m))
             tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
             rgb_means = its.image.compute_image_means(tile)
-            r_means.append(rgb_means[0])
-            g_means.append(rgb_means[1])
-            b_means.append(rgb_means[2])
+            # Adjust for the difference between request and result
+            r_means.append(rgb_means[0] * request_result_ratio)
+            g_means.append(rgb_means[1] * request_result_ratio)
+            b_means.append(rgb_means[2] * request_result_ratio)
             # Test 3 steps per 2x gain
             m = m * pow(2, 1.0 / 3)
 
@@ -73,9 +87,9 @@
             threshold_max_level_diff = THRESHOLD_MAX_LEVEL_DIFF_WIDE_RANGE
 
     # Draw a plot.
-    pylab.plot(mults, r_means, 'r')
-    pylab.plot(mults, g_means, 'g')
-    pylab.plot(mults, b_means, 'b')
+    pylab.plot(mults, r_means, 'r.-')
+    pylab.plot(mults, g_means, 'g.-')
+    pylab.plot(mults, b_means, 'b.-')
     pylab.ylim([0,1])
     matplotlib.pyplot.savefig("%s_plot_means.png" % (NAME))
 
diff --git a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
index 35cfc07..1072684 100644
--- a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
@@ -35,12 +35,13 @@
     """
     NAME = os.path.basename(__file__).split(".")[0]
 
-    RELATIVE_ERROR_TOLERANCE = 0.1
-    # List of variances for R,G,B.
-    variances = [[],[],[]]
+    NUM_SAMPLES_PER_MODE = 4
+    SNR_TOLERANCE = 3 # unit in db
+    # List of SNRs for R,G,B.
+    snrs = [[], [], []]
 
-    # Reference (baseline) variance for each of R,G,B.
-    ref_variance = []
+    # Reference (baseline) SNR for each of R,G,B.
+    ref_snr = []
 
     nr_modes_reported = []
 
@@ -60,8 +61,8 @@
                 rgb_image,
                 "%s_low_gain.jpg" % (NAME))
         rgb_tile = its.image.get_image_patch(rgb_image, 0.45, 0.45, 0.1, 0.1)
-        ref_variance = its.image.compute_image_variances(rgb_tile)
-        print "Ref variances:", ref_variance
+        ref_snr = its.image.compute_image_snrs(rgb_tile)
+        print "Ref SNRs:", ref_snr
 
         e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
         # NR modes 0, 1, 2, 3, 4 with high gain
@@ -70,58 +71,74 @@
             if not its.caps.noise_reduction_mode(props, mode):
                 nr_modes_reported.append(mode)
                 for channel in range(3):
-                    variances[channel].append(0)
+                    snrs[channel].append(0)
                 continue;
 
-            req = its.objects.manual_capture_request(s, e)
-            req["android.noiseReduction.mode"] = mode
-            cap = cam.do_capture(req)
-            rgb_image = its.image.convert_capture_to_rgb_image(cap)
-            nr_modes_reported.append(
-                    cap["metadata"]["android.noiseReduction.mode"])
-            its.image.write_image(
-                    rgb_image,
-                    "%s_high_gain_nr=%d.jpg" % (NAME, mode))
-            rgb_tile = its.image.get_image_patch(
-                    rgb_image, 0.45, 0.45, 0.1, 0.1)
-            rgb_vars = its.image.compute_image_variances(rgb_tile)
+            rgb_snr_list = []
+            # Capture several images to account for per frame noise variations
+            for n in range(NUM_SAMPLES_PER_MODE):
+                req = its.objects.manual_capture_request(s, e)
+                req["android.noiseReduction.mode"] = mode
+                cap = cam.do_capture(req)
+                rgb_image = its.image.convert_capture_to_rgb_image(cap)
+                if n == 0:
+                    nr_modes_reported.append(
+                            cap["metadata"]["android.noiseReduction.mode"])
+                    its.image.write_image(
+                            rgb_image,
+                            "%s_high_gain_nr=%d.jpg" % (NAME, mode))
+                rgb_tile = its.image.get_image_patch(
+                        rgb_image, 0.45, 0.45, 0.1, 0.1)
+                rgb_snrs = its.image.compute_image_snrs(rgb_tile)
+                rgb_snr_list.append(rgb_snrs)
+
+            r_snrs = [rgb[0] for rgb in rgb_snr_list]
+            g_snrs = [rgb[1] for rgb in rgb_snr_list]
+            b_snrs = [rgb[2] for rgb in rgb_snr_list]
+            rgb_snrs = [numpy.mean(r_snrs), numpy.mean(g_snrs), numpy.mean(b_snrs)]
+            print "NR mode", mode, "SNRs:"
+            print "    R SNR:", rgb_snrs[0],\
+                    "Min:", min(r_snrs), "Max:", max(r_snrs)
+            print "    G SNR:", rgb_snrs[1],\
+                    "Min:", min(g_snrs), "Max:", max(g_snrs)
+            print "    B SNR:", rgb_snrs[2],\
+                    "Min:", min(b_snrs), "Max:", max(b_snrs)
+
             for chan in range(3):
-                variance = rgb_vars[chan]
-                variances[chan].append(variance / ref_variance[chan])
-        print "Variances with NR mode [0,1,2]:", variances
+                snrs[chan].append(rgb_snrs[chan])
 
     # Draw a plot.
     for j in range(3):
-        pylab.plot(range(5), variances[j], "rgb"[j])
-    matplotlib.pyplot.savefig("%s_plot_variances.png" % (NAME))
+        pylab.plot(range(5), snrs[j], "rgb"[j])
+    matplotlib.pyplot.savefig("%s_plot_SNRs.png" % (NAME))
 
     assert(nr_modes_reported == [0,1,2,3,4])
 
     for j in range(3):
-        # Smaller variance is better
+        # Larger SNR is better
         # Verify OFF(0) is not better than FAST(1)
-        assert(variances[j][0] >
-               variances[j][1] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+        assert(snrs[j][0] <
+               snrs[j][1] + SNR_TOLERANCE)
         # Verify FAST(1) is not better than HQ(2)
-        assert(variances[j][1] >
-               variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+        assert(snrs[j][1] <
+               snrs[j][2] + SNR_TOLERANCE)
         # Verify HQ(2) is better than OFF(0)
-        assert(variances[j][0] > variances[j][2])
+        assert(snrs[j][0] < snrs[j][2])
         if its.caps.noise_reduction_mode(props, 3):
             # Verify OFF(0) is not better than MINIMAL(3)
-            assert(variances[j][0] >
-                   variances[j][3] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+            assert(snrs[j][0] <
+                   snrs[j][3] + SNR_TOLERANCE)
             # Verify MINIMAL(3) is not better than HQ(2)
-            assert(variances[j][3] >
-                   variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+            assert(snrs[j][3] <
+                   snrs[j][2] + SNR_TOLERANCE)
             if its.caps.noise_reduction_mode(props, 4):
                 # Verify ZSL(4) is close to MINIMAL(3)
-                assert(numpy.isclose(variances[j][4], variances[j][3],
-                                     RELATIVE_ERROR_TOLERANCE))
+                assert(numpy.isclose(snrs[j][4], snrs[j][3],
+                                     atol=SNR_TOLERANCE))
         elif its.caps.noise_reduction_mode(props, 4):
             # Verify ZSL(4) is close to OFF(0)
-            assert(numpy.isclose(variances[j][4], variances[j][0],
-                                 RELATIVE_ERROR_TOLERANCE))
+            assert(numpy.isclose(snrs[j][4], snrs[j][0],
+                                 atol=SNR_TOLERANCE))
 
 if __name__ == '__main__':
     main()
diff --git a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
index 6c2b5c1..e176312 100644
--- a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
@@ -44,6 +44,8 @@
 
         # Expose for the scene with min sensitivity
         sens_min, sens_max = props['android.sensor.info.sensitivityRange']
+        # Digital gains might not be visible on RAW data
+        sens_max = props['android.sensor.maxAnalogSensitivity']
         sens_step = (sens_max - sens_min) / NUM_STEPS
         s_ae,e_ae,_,_,_  = cam.do_3a(get_results=True)
         s_e_prod = s_ae * e_ae
diff --git a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
index 14c5eb0..cc0ce14 100644
--- a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
@@ -42,6 +42,8 @@
 
         # Expose for the scene with min sensitivity
         sens_min, sens_max = props['android.sensor.info.sensitivityRange']
+        # Digital gains might not be visible on RAW data
+        sens_max = props['android.sensor.maxAnalogSensitivity']
         sens_step = (sens_max - sens_min) / NUM_STEPS
         s_ae,e_ae,_,_,_  = cam.do_3a(get_results=True)
         s_e_prod = s_ae * e_ae
diff --git a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
index 757dfeb..f0a6fbe 100644
--- a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
@@ -38,7 +38,8 @@
 
     NAME = os.path.basename(__file__).split(".")[0]
 
-    RELATIVE_ERROR_TOLERANCE = 0.1
+    NUM_SAMPLES_PER_MODE = 4
+    SNR_TOLERANCE = 3 # unit in db
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
@@ -60,7 +61,7 @@
 
         for reprocess_format in reprocess_formats:
             # List of variances for R, G, B.
-            variances = []
+            snrs = [[], [], []]
             nr_modes_reported = []
 
             # NR mode 0 with low gain
@@ -77,71 +78,90 @@
             img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
             its.image.write_image(img, "%s_low_gain_fmt=jpg.jpg" % (NAME))
             tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
-            ref_variance = its.image.compute_image_variances(tile)
-            print "Ref variances:", ref_variance
+            ref_snr = its.image.compute_image_snrs(tile)
+            print "Ref SNRs:", ref_snr
 
+            e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
             for nr_mode in range(5):
                 # Skip unavailable modes
                 if not its.caps.noise_reduction_mode(props, nr_mode):
                     nr_modes_reported.append(nr_mode)
-                    variances.append(0)
+                    for channel in range(3):
+                        snrs[channel].append(0)
                     continue
 
-                # NR modes with high gain
-                e, s = its.target.get_target_exposure_combos(cam) \
-                    ["maxSensitivity"]
-                req = its.objects.manual_capture_request(s, e)
-                req["android.noiseReduction.mode"] = nr_mode
-                cap = cam.do_capture(req, out_surface, reprocess_format)
-                nr_modes_reported.append(
-                    cap["metadata"]["android.noiseReduction.mode"])
+                rgb_snr_list = []
+                # Capture several images to account for per frame noise
+                # variations
+                for n in range(NUM_SAMPLES_PER_MODE):
+                    req = its.objects.manual_capture_request(s, e)
+                    req["android.noiseReduction.mode"] = nr_mode
+                    cap = cam.do_capture(req, out_surface, reprocess_format)
 
-                img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
-                its.image.write_image(
-                    img, "%s_high_gain_nr=%d_fmt=jpg.jpg" % (NAME, nr_mode))
-                tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
-                # Get the variances for R, G, and B channels
-                variance = its.image.compute_image_variances(tile)
-                variances.append(
-                    [variance[chan] / ref_variance[chan] for chan in range(3)])
-            print "Variances with NR mode [0,1,2,3,4]:", variances
+                    img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
+                    if n == 0:
+                        its.image.write_image(
+                                img,
+                                "%s_high_gain_nr=%d_fmt=jpg.jpg"
+                                        %(NAME, nr_mode))
+                        nr_modes_reported.append(
+                                cap["metadata"]["android.noiseReduction.mode"])
+
+                    tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+                    # Get the variances for R, G, and B channels
+                    rgb_snrs = its.image.compute_image_snrs(tile)
+                    rgb_snr_list.append(rgb_snrs)
+
+                r_snrs = [rgb[0] for rgb in rgb_snr_list]
+                g_snrs = [rgb[1] for rgb in rgb_snr_list]
+                b_snrs = [rgb[2] for rgb in rgb_snr_list]
+                rgb_snrs = [numpy.mean(r_snrs),
+                            numpy.mean(g_snrs),
+                            numpy.mean(b_snrs)]
+                print "NR mode", nr_mode, "SNRs:"
+                print "    R SNR:", rgb_snrs[0],\
+                        "Min:", min(r_snrs), "Max:", max(r_snrs)
+                print "    G SNR:", rgb_snrs[1],\
+                        "Min:", min(g_snrs), "Max:", max(g_snrs)
+                print "    B SNR:", rgb_snrs[2],\
+                        "Min:", min(b_snrs), "Max:", max(b_snrs)
+
+                for chan in range(3):
+                    snrs[chan].append(rgb_snrs[chan])
 
             # Draw a plot.
-            for chan in range(3):
-                line = []
-                for nr_mode in range(5):
-                    line.append(variances[nr_mode][chan])
-                pylab.plot(range(5), line, "rgb"[chan])
+            for channel in range(3):
+                pylab.plot(range(5), snrs[channel], "rgb"[channel])
 
-            matplotlib.pyplot.savefig("%s_plot_%s_variances.png" %
+            matplotlib.pyplot.savefig("%s_plot_%s_SNRs.png" %
                                       (NAME, reprocess_format))
 
             assert(nr_modes_reported == [0,1,2,3,4])
 
             for j in range(3):
-                # Smaller variance is better
+                # Larger is better
                 # Verify OFF(0) is not better than FAST(1)
-                assert(variances[0][j] >
-                       variances[1][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+                assert(snrs[j][0] <
+                       snrs[j][1] + SNR_TOLERANCE)
                 # Verify FAST(1) is not better than HQ(2)
-                assert(variances[1][j] >
-                       variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+                assert(snrs[j][1] <
+                       snrs[j][2] + SNR_TOLERANCE)
                 # Verify HQ(2) is better than OFF(0)
-                assert(variances[0][j] > variances[2][j])
+                assert(snrs[j][0] < snrs[j][2])
                 if its.caps.noise_reduction_mode(props, 3):
                     # Verify OFF(0) is not better than MINIMAL(3)
-                    assert(variances[0][j] >
-                           variances[3][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+                    assert(snrs[j][0] <
+                           snrs[j][3] + SNR_TOLERANCE)
                     # Verify MINIMAL(3) is not better than HQ(2)
-                    assert(variances[3][j] >
-                           variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+                    assert(snrs[j][3] <
+                           snrs[j][2] + SNR_TOLERANCE)
                     # Verify ZSL(4) is close to MINIMAL(3)
-                    assert(numpy.isclose(variances[4][j], variances[3][j],
-                                         RELATIVE_ERROR_TOLERANCE))
+                    assert(numpy.isclose(snrs[j][4], snrs[j][3],
+                                         atol=SNR_TOLERANCE))
                 else:
                     # Verify ZSL(4) is close to OFF(0)
-                    assert(numpy.isclose(variances[4][j], variances[0][j],
-                                         RELATIVE_ERROR_TOLERANCE))
+                    assert(numpy.isclose(snrs[j][4], snrs[j][0],
+                                         atol=SNR_TOLERANCE))
 
 if __name__ == '__main__':
     main()
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
index 33e7763..268b64a 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
@@ -31,6 +31,12 @@
         cam.do_3a()
 
         req = its.objects.auto_capture_request()
+        max_dng_size = \
+                its.objects.get_available_output_sizes("raw", props)[0]
+        w,h = its.objects.get_available_output_sizes(
+                "yuv", props, (1920, 1080), max_dng_size)[0]
+        out_surfaces = [{"format":"dng"},
+                        {"format":"yuv", "width":w, "height":h}]
         cap_dng, cap_yuv = cam.do_capture(req, cam.CAP_DNG_YUV)
 
         img = its.image.convert_capture_to_rgb_image(cap_yuv)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
index 9ce8d76..78378eb 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
@@ -27,13 +27,17 @@
 
     THRESHOLD_MAX_RMS_DIFF = 0.01
 
-    fmt_yuv =  {"format":"yuv"}
-    fmt_jpeg = {"format":"jpeg"}
-
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
         its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
+        max_jpeg_size = \
+                its.objects.get_available_output_sizes("jpeg", props)[0]
+        w,h = its.objects.get_available_output_sizes(
+                "yuv", props, (1920, 1080), max_jpeg_size)[0]
+        fmt_yuv =  {"format":"yuv", "width":w, "height":h}
+        fmt_jpeg = {"format":"jpeg"}
+
         # Use a manual request with a linear tonemap so that the YUV and JPEG
         # should look the same (once converted by the its.image module).
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
index f13801b..bfa6a28 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
@@ -38,7 +38,13 @@
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
         req = its.objects.manual_capture_request(s, e, True, props)
 
-        cap_raw, cap_yuv = cam.do_capture(req, cam.CAP_RAW_YUV)
+        max_raw_size = \
+                its.objects.get_available_output_sizes("raw", props)[0]
+        w,h = its.objects.get_available_output_sizes(
+                "yuv", props, (1920, 1080), max_raw_size)[0]
+        out_surfaces = [{"format":"raw"},
+                        {"format":"yuv", "width":w, "height":h}]
+        cap_raw, cap_yuv = cam.do_capture(req, out_surfaces)
 
         img = its.image.convert_capture_to_rgb_image(cap_yuv)
         its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
index e52946d..322af10 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
@@ -38,8 +38,13 @@
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
         req = its.objects.manual_capture_request(s, e, True, props)
 
+        max_raw10_size = \
+                its.objects.get_available_output_sizes("raw10", props)[0]
+        w,h = its.objects.get_available_output_sizes(
+                "yuv", props, (1920, 1080), max_raw10_size)[0]
         cap_raw, cap_yuv = cam.do_capture(req,
-                [{"format":"raw10"}, {"format":"yuv"}])
+                [{"format":"raw10"},
+                 {"format":"yuv", "width":w, "height":h}])
 
         img = its.image.convert_capture_to_rgb_image(cap_yuv)
         its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
index c5c3c73..b3cca0b 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
@@ -38,8 +38,13 @@
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
         req = its.objects.manual_capture_request(s, e, True, props)
 
+        max_raw12_size = \
+                its.objects.get_available_output_sizes("raw12", props)[0]
+        w,h = its.objects.get_available_output_sizes(
+                "yuv", props, (1920, 1080), max_raw12_size)[0]
         cap_raw, cap_yuv = cam.do_capture(req,
-                [{"format":"raw12"}, {"format":"yuv"}])
+                [{"format":"raw12"},
+                 {"format":"yuv", "width":w, "height":h}])
 
         img = its.image.convert_capture_to_rgb_image(cap_yuv)
         its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index 73834cb..e96a9ee 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -53,22 +53,28 @@
     """
 
     NAME = os.path.basename(__file__).split(".")[0]
+    NUM_SAMPLES = 4
 
     req = its.objects.manual_capture_request(sensitivity, exp)
     req["android.lens.focusDistance"] = fd
     req["android.edge.mode"] = edge_mode
     if (reprocess_format != None):
         req["android.reprocess.effectiveExposureFactor"] = 1.0
-    cap = cam.do_capture(req, out_surface, reprocess_format)
 
-    img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
-    its.image.write_image(img, "%s_edge=%d_reprocess_fmt_%s.jpg" %
-        (NAME, edge_mode, reprocess_format))
-    tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+    sharpness_list = []
+    for n in range(NUM_SAMPLES):
+        cap = cam.do_capture(req, out_surface, reprocess_format)
+        img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
+        if n == 0:
+            its.image.write_image(img, "%s_reprocess_fmt_%s_edge=%d.jpg" %
+                (NAME, reprocess_format, edge_mode))
+            res_edge_mode = cap["metadata"]["android.edge.mode"]
+        tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+        sharpness_list.append(its.image.compute_image_sharpness(tile))
 
     ret = {}
-    ret["edge_mode"] = cap["metadata"]["android.edge.mode"]
-    ret["sharpness"] = its.image.compute_image_sharpness(tile)
+    ret["edge_mode"] = res_edge_mode
+    ret["sharpness"] = numpy.mean(sharpness_list)
 
     return ret
 
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 8cec7ea..34246cc 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -41,7 +41,7 @@
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 
-LOCAL_AAPT_FLAGS += --version-name "6.0_r0 $(BUILD_NUMBER)"
+LOCAL_AAPT_FLAGS += --version-name "6.0_r1 $(BUILD_NUMBER)"
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni libaudioloopback_jni
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 5c188b7..5e8ab90 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -363,6 +363,7 @@
             <meta-data android:name="test_category" android:value="@string/test_category_security" />
             <meta-data android:name="test_excluded_features"
                        android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.fingerprint" />
         </activity>
         <activity android:name=".security.ScreenLockBoundKeysTest"
                 android:label="@string/sec_lock_bound_key_test"
@@ -753,7 +754,7 @@
             android:screenOrientation="locked" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST_disabled"/>
             </intent-filter>
 
             <meta-data
@@ -762,8 +763,6 @@
             <meta-data
                 android:name="test_required_features"
                 android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.gyroscope:android.hardware.sensor.compass:android.hardware.camera.any" />
-            <meta-data android:name="test_excluded_features"
-                    android:value="android.hardware.type.television" />
         </activity>
         <activity
             android:name=".sensors.RVCVRecordActivity"
@@ -1397,6 +1396,13 @@
             </intent-filter>
         </activity-alias>
 
+        <activity android:name=".managedprovisioning.AuthenticationBoundKeyTestActivity">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.AUTH_BOUND_KEY_TEST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".managedprovisioning.ByodFlowTestActivity"
                 android:launchMode="singleTask"
                 android:label="@string/provisioning_byod">
@@ -1424,6 +1430,8 @@
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.TEST_NFC_BEAM" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
         </activity>
@@ -1451,11 +1459,87 @@
 
         <activity android:name=".managedprovisioning.CrossProfileTestActivity">
             <intent-filter>
-                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE" />
-                <!-- We need to have at least one activity listening to this intent in the parent
-                     to test if it is forwarded from the managed profile to the parent -->
+                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK" />
+                <!-- We need to have at least one activity listening to these intents on the device
+                     to test if these are forwarded from the managed profile to the parent or
+                     the other way around. -->
                 <action android:name="android.provider.MediaStore.RECORD_SOUND" />
-                <category android:name="android.intent.category.DEFAULT"></category>
+                <action android:name="android.speech.action.RECOGNIZE_SPEECH" />
+                <action android:name="android.app.action.SET_NEW_PASSWORD" />
+                <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
+                <action android:name="android.intent.action.WEB_SEARCH" />
+                <action android:name="android.intent.action.VIEW_DOWNLOADS" />
+                <action android:name="android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL" />
+                <action android:name="android.settings.SHOW_INPUT_METHOD_PICKER" />
+                <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
+                <action android:name="com.android.settings.TTS_SETTINGS" />
+                <action android:name="android.settings.ZEN_MODE_SETTINGS" />
+                <action android:name="android.settings.BATTERY_SAVER_SETTINGS" />
+                <action android:name="android.settings.INPUT_METHOD_SETTINGS" />
+                <action android:name="android.settings.INPUT_METHOD_SUBTYPE_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.SEND" />
+                <action android:name="android.intent.action.SEND_MULTIPLE" />
+                <data android:mimeType="*/*" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.GET_CONTENT" />
+                <action android:name="android.intent.action.OPEN_DOCUMENT" />
+                <data android:mimeType="*/*" />
+                <category android:name="android.intent.category.OPENABLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <action android:name="android.intent.action.SENDTO" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="sms" />
+                <data android:scheme="smsto" />
+                <data android:scheme="mms" />
+                <data android:scheme="mmsto" />
+                <data android:scheme="mailto" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <action android:name="android.intent.action.CALL" />
+                <action android:name="android.intent.action.DIAL" />
+                <action android:name="android.intent.action.CALL_PRIVILEGED" />
+                <action android:name="android.intent.action.CALL_EMERGENCY" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="tel" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.INSERT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="content" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="http" android:host="com.android.cts.verifier" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="http" />
+                <data android:mimeType="video/mp4" />
+                <data android:mimeType="audio/*" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="http" />
+                <data android:scheme="geo" />
+                <data android:scheme="market" />
             </intent-filter>
         </activity>
 
@@ -1573,6 +1657,18 @@
                     android:value="android.software.live_tv" />
         </activity>
 
+        <activity android:name=".tv.AppLinkTestActivity"
+            android:label="@string/tv_app_link_test"
+            android:launchMode="singleTask">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_tv" />
+            <meta-data android:name="test_required_features"
+                android:value="android.software.live_tv" />
+        </activity>
+
         <activity android:name=".screenpinning.ScreenPinningTestActivity"
             android:label="@string/screen_pinning_test">
             <intent-filter>
@@ -1612,30 +1708,46 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
         </activity>
 
-        <activity android:name=".audio.AudioDeviceNotificationsActivity"
-                  android:label="@string/audio_devices_notifications_test">
+        <activity android:name=".audio.AudioOutputDeviceNotificationsActivity"
+                  android:label="@string/audio_out_devices_notifications_test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_audio" />
-            <!--
-            <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
-            -->
+            <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
         </activity>
 
-        <activity android:name=".audio.AudioRoutingNotificationsActivity"
-                  android:label="@string/audio_routingnotifications_test">
+        <activity android:name=".audio.AudioInputDeviceNotificationsActivity"
+                  android:label="@string/audio_in_devices_notifications_test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_audio" />
-            <!--
             <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
-            -->
         </activity>
 
+        <activity android:name=".audio.AudioOutputRoutingNotificationsActivity"
+                  android:label="@string/audio_output_routingnotifications_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
+            </activity>
+
+        <activity android:name=".audio.AudioInputRoutingNotificationsActivity"
+                  android:label="@string/audio_input_routingnotifications_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+            </activity>
+
         <activity android:name=".audio.AudioLoopbackActivity"
                   android:label="@string/audio_loopback_test">
             <intent-filter>
@@ -1644,6 +1756,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_audio" />
             <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
             <meta-data android:name="test_excluded_features" android:value="android.hardware.type.watch" />
             <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
         </activity>
diff --git a/apps/CtsVerifier/jni/verifier/Android.mk b/apps/CtsVerifier/jni/verifier/Android.mk
index da4687d..4840e62 100644
--- a/apps/CtsVerifier/jni/verifier/Android.mk
+++ b/apps/CtsVerifier/jni/verifier/Android.mk
@@ -25,8 +25,11 @@
 
 LOCAL_SRC_FILES := \
 		CtsVerifierJniOnLoad.cpp \
-		com_android_cts_verifier_os_FileUtils.cpp	
+		com_android_cts_verifier_camera_StatsImage.cpp \
+		com_android_cts_verifier_os_FileUtils.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
+LOCAL_SHARED_LIBRARIES := liblog
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp b/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp
index 81e5690..399275b 100644
--- a/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp
+++ b/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2010 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,7 @@
 #include <stdio.h>
 
 extern int register_com_android_cts_verifier_os_FileUtils(JNIEnv*);
+extern int register_com_android_cts_verifier_camera_its_StatsImage(JNIEnv*);
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
@@ -30,5 +31,9 @@
         return JNI_ERR;
     }
 
+    if (register_com_android_cts_verifier_camera_its_StatsImage(env)) {
+        return JNI_ERR;
+    }
+
     return JNI_VERSION_1_4;
 }
diff --git a/apps/CtsVerifier/jni/verifier/com_android_cts_verifier_camera_StatsImage.cpp b/apps/CtsVerifier/jni/verifier/com_android_cts_verifier_camera_StatsImage.cpp
new file mode 100644
index 0000000..16dff85
--- /dev/null
+++ b/apps/CtsVerifier/jni/verifier/com_android_cts_verifier_camera_StatsImage.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "ITS-StatsImage-JNI"
+// #define LOG_NDEBUG 0
+#include <android/log.h>
+#include <utils/Log.h>
+
+#include <jni.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include <string.h>
+
+jfloatArray com_android_cts_verifier_camera_its_computeStatsImage(JNIEnv* env, jobject thiz,
+        jbyteArray img, jint width, jint height, jint gridWidth, jint gridHeight)
+{
+    int bufSize = (int)(env->GetArrayLength(img));
+    unsigned char *buf = (unsigned char*)env->GetByteArrayElements(img, /*is_copy*/NULL);
+
+    // Size of the raw image.
+    const int w = width;
+    const int h = height;
+    // Size of each grid cell.
+    const int gw = gridWidth;
+    const int gh = gridHeight;
+    // Number of grid cells (rounding down to full cells only at right+bottom edges).
+    const int ngx = w / gw;
+    const int ngy = h / gh;
+
+    float *mean = new float[ngy*ngx*4];
+    float *var = new float[ngy*ngx*4];
+    for (int gy = 0; gy < ngy; gy++) {
+        for (int gx = 0; gx < ngx; gx++) {
+            float sum[4] = {0};
+            float sumSq[4] = {0};
+            int count[4] = {0};
+            for (int y = gy*gh; y < (gy+1)*gh; y++) {
+                int chnOffset = (y & 0x1) * 2;
+                unsigned char *pbuf = buf + 2*y*w + 2*gx*gw;
+                for (int x = gx*gw; x < (gx+1)*gw; x++) {
+                    // input is RAW16
+                    int byte0 = *pbuf++;
+                    int byte1 = *pbuf++;
+                    int pixelValue = (byte1 << 8) | byte0;
+                    int ch = chnOffset + (x & 1);
+                    sum[ch] += pixelValue;
+                    sumSq[ch] += pixelValue * pixelValue;
+                    count[ch] += 1;
+                }
+            }
+            for (int ch = 0; ch < 4; ch++) {
+                float m = (float)sum[ch] / count[ch];
+                float mSq = (float)sumSq[ch] / count[ch];
+                mean[gy*ngx*4 + gx*4 + ch] = m;
+                var[gy*ngx*4 + gx*4 + ch] = mSq - m*m;
+            }
+        }
+    }
+
+    jfloatArray ret = env->NewFloatArray(ngx*ngy*4*2);
+    env->SetFloatArrayRegion(ret, 0, ngx*ngy*4, (float*)mean);
+    env->SetFloatArrayRegion(ret, ngx*ngy*4, ngx*ngy*4, (float*)var);
+    delete [] mean;
+    delete [] var;
+    return ret;
+}
+
+static JNINativeMethod gMethods[] = {
+    {  "computeStatsImage", "([BIIII)[F",
+            (void *) com_android_cts_verifier_camera_its_computeStatsImage  },
+};
+
+int register_com_android_cts_verifier_camera_its_StatsImage(JNIEnv* env)
+{
+    jclass clazz = env->FindClass("com/android/cts/verifier/camera/its/StatsImage");
+
+    return env->RegisterNatives(clazz, gMethods,
+            sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/apps/CtsVerifier/res/drawable/app_link_img.png b/apps/CtsVerifier/res/drawable/app_link_img.png
new file mode 100644
index 0000000..851fc6f
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/app_link_img.png
Binary files differ
diff --git a/apps/CtsVerifier/res/layout/audio_dev_notify.xml b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
index 98dbd8b..ceedf1c 100644
--- a/apps/CtsVerifier/res/layout/audio_dev_notify.xml
+++ b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
@@ -13,19 +13,51 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/scrollView"
+    >
+
+<LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:padding="10dip"
+        android:padding="20dp"
         android:orientation="vertical">
 
-  <TextView
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbars="vertical"
+            android:gravity="bottom"
+            android:id="@+id/audio_general_headset_port_exists"
+            android:text="@string/audio_general_headset_port_exists" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_general_headset_no"
+                android:text="@string/audio_general_headset_no" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_general_headset_yes"
+                android:text="@string/audio_general_headset_yes" />
+        </LinearLayout>
+
+    <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:scrollbars="vertical"
       android:gravity="bottom"
-      android:id="@+id/info_text"
-      android:text="@string/audio_devices_notification_instructions" />
+      android:id="@+id/info_text"/>
 
   <LinearLayout
       android:layout_width="match_parent"
@@ -51,4 +83,5 @@
 
   <include layout="@layout/pass_fail_buttons" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
index 69e3bc7..c1b62af 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
@@ -13,60 +13,105 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="10dip"
+    android:orientation="vertical"
+>
+    <ScrollView
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:padding="10dip"
-        android:orientation="vertical">
+        android:layout_height="match_parent"
+        android:id="@+id/scrollView"
+    >
 
-  <TextView
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:scrollbars="vertical"
-      android:gravity="bottom"
-      android:id="@+id/info_text"
-      android:text="@string/audio_frequency_line_instructions" />
-  <LinearLayout
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical">
-      <Button
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:id="@+id/audio_frequency_line_plug_ready_btn"
-          android:text="@string/audio_frequency_line_plug_ready_btn"/>
-
-    <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-     <LinearLayout
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:orientation="horizontal"
-          android:id="@+id/audio_frequency_line_layout">
-            <Button
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/audio_frequency_line_test_btn"
-                android:id="@+id/audio_frequency_line_test_btn"/>
-
-            <ProgressBar
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:id="@+id/audio_frequency_line_progress_bar"/>
-        </LinearLayout>
-
-        <TextView
-            android:layout_width="wrap_content"
+        <LinearLayout
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="@string/audio_frequency_line_results_text"
-            android:id="@+id/audio_frequency_line_results_text"/>
+            android:orientation="vertical"
+        >
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:scrollbars="vertical"
+                android:gravity="bottom"
+                android:id="@+id/audio_general_headset_port_exists"
+                android:text="@string/audio_general_headset_port_exists" />
 
-    </LinearLayout>
-    </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+            >
 
-  <include layout="@layout/pass_fail_buttons" />
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_general_headset_no"
+                    android:text="@string/audio_general_headset_no" />
+
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_general_headset_yes"
+                    android:text="@string/audio_general_headset_yes" />
+
+            </LinearLayout>
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:scrollbars="vertical"
+                android:gravity="bottom"
+                android:id="@+id/info_text"
+                android:text="@string/audio_frequency_line_instructions" />
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+            >
+                <Button
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_frequency_line_plug_ready_btn"
+                    android:text="@string/audio_frequency_line_plug_ready_btn" />
+
+                <LinearLayout
+                    android:orientation="vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                >
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal"
+                        android:id="@+id/audio_frequency_line_layout"
+                    >
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/audio_frequency_line_test_btn"
+                            android:id="@+id/audio_frequency_line_test_btn" />
+
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:id="@+id/audio_frequency_line_progress_bar" />
+                    </LinearLayout>
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/audio_frequency_line_results_text"
+                        android:id="@+id/audio_frequency_line_results_text" />
+
+                </LinearLayout>
+            </LinearLayout>
+
+            <include layout="@layout/pass_fail_buttons" />
+        </LinearLayout>
+    </ScrollView>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
index 10b0003..db52998 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
@@ -18,116 +18,151 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:padding="10dip"
-    android:orientation="vertical">
+    android:orientation="vertical"
+>
 
     <ScrollView
-       android:layout_width="match_parent"
-       android:layout_height="match_parent"
-       android:id="@+id/scrollView">
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/scrollView"
+    >
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:orientation="vertical">
+            android:orientation="vertical"
+        >
 
-        <LinearLayout
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:scrollbars="vertical"
+                android:gravity="bottom"
+                android:id="@+id/audio_general_headset_port_exists"
+                android:text="@string/audio_general_headset_port_exists" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+            >
+
+                <Button
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:orientation="horizontal">
-          <TextView
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:layout_weight="1"
-              android:id="@+id/info_text"
-              android:text="@string/audio_frequency_mic_instructions"/>
+                    android:id="@+id/audio_general_headset_no"
+                    android:text="@string/audio_general_headset_no" />
 
-           <ProgressBar
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_weight="1"
-                        android:id="@+id/audio_frequency_mic_progress_bar"/>
-         </LinearLayout>
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_general_headset_yes"
+                    android:text="@string/audio_general_headset_yes" />
 
-          <Button
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:id="@+id/audio_frequency_mic_speakers_ready_btn"
-              android:text="@string/audio_frequency_mic_speakers_ready_btn"/>
+            </LinearLayout>
 
-          <TextView
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+            >
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:id="@+id/info_text"
+                    android:text="@string/audio_frequency_mic_instructions" />
+
+                <ProgressBar
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:id="@+id/audio_frequency_mic_progress_bar" />
+            </LinearLayout>
+
+            <Button
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_frequency_mic_speakers_ready_btn"
+                android:text="@string/audio_frequency_mic_speakers_ready_btn" />
+
+            <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:scrollbars="vertical"
                 android:gravity="bottom"
                 android:id="@+id/audio_frequency_mic_speakers_ready_status"
-                android:text="@string/audio_frequency_mic_speakers_ready_status"/>
+                android:text="@string/audio_frequency_mic_speakers_ready_status" />
 
             <LinearLayout
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
-                android:id="@+id/audio_frequency_mic_layout_test1">
+                android:id="@+id/audio_frequency_mic_layout_test1"
+            >
 
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/audio_frequency_mic_instructions2"
-                android:id="@+id/audio_frequency_mic_instructions2"/>
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/audio_frequency_mic_instructions2"
+                    android:id="@+id/audio_frequency_mic_instructions2" />
 
-              <Button
+                <Button
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:text="@string/audio_frequency_mic_test1_btn"
-                    android:id="@+id/audio_frequency_mic_test1_btn"/>
+                    android:id="@+id/audio_frequency_mic_test1_btn" />
 
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:text="@string/audio_frequency_mic_results_text"
-                    android:id="@+id/audio_frequency_mic_results1_text"/>
-          </LinearLayout>
+                    android:id="@+id/audio_frequency_mic_results1_text" />
+            </LinearLayout>
 
-          <LinearLayout
+            <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
-                android:id="@+id/audio_frequency_mic_layout_test2a">
+                android:id="@+id/audio_frequency_mic_layout_test2a"
+            >
 
-            <Button
+                <Button
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_frequency_mic_mic_ready_btn"
+                    android:text="@string/audio_frequency_mic_mic_ready_btn" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/audio_frequency_mic_usb_status"
+                    android:id="@+id/audio_frequency_mic_usb_status" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:orientation="vertical"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:id="@+id/audio_frequency_mic_mic_ready_btn"
-                android:text="@string/audio_frequency_mic_mic_ready_btn"/>
+                android:layout_height="match_parent"
+                android:id="@+id/audio_frequency_mic_layout_test2b"
+            >
 
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/audio_frequency_mic_usb_status"
-                android:id="@+id/audio_frequency_mic_usb_status"/>
-           </LinearLayout>
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/audio_frequency_mic_test2_btn"
+                    android:id="@+id/audio_frequency_mic_test2_btn" />
 
-          <LinearLayout
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:id="@+id/audio_frequency_mic_layout_test2b">
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/audio_frequency_mic_results_text"
+                    android:id="@+id/audio_frequency_mic_results_text" />
 
-            <Button
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/audio_frequency_mic_test2_btn"
-                android:id="@+id/audio_frequency_mic_test2_btn"/>
+            </LinearLayout>
 
-              <TextView
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:text="@string/audio_frequency_mic_results_text"
-                  android:id="@+id/audio_frequency_mic_results_text"/>
-
+            <include layout="@layout/pass_fail_buttons" />
         </LinearLayout>
-
-        <include layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-      </ScrollView>
+    </ScrollView>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml b/apps/CtsVerifier/res/layout/audio_input_routingnotifications_test.xml
similarity index 61%
copy from apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
copy to apps/CtsVerifier/res/layout/audio_input_routingnotifications_test.xml
index cef30d6..60a12ef 100644
--- a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
+++ b/apps/CtsVerifier/res/layout/audio_input_routingnotifications_test.xml
@@ -14,52 +14,51 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/scrollView"
+    >
+
+<LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:padding="10dip"
+        android:padding = "20dp"
         android:orientation="vertical">
 
-  <TextView
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbars="vertical"
+            android:gravity="bottom"
+            android:id="@+id/audio_general_headset_port_exists"
+            android:text="@string/audio_general_headset_port_exists" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_general_headset_no"
+                android:text="@string/audio_general_headset_no" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_general_headset_yes"
+                android:text="@string/audio_general_headset_yes" />
+        </LinearLayout>
+
+    <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:scrollbars="vertical"
       android:gravity="bottom"
       android:id="@+id/info_text"
-      android:text="@string/audio_dev_routingnotification_instructions" />
-
-  <LinearLayout
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical"
-      android:id="@+id/audioTrackRoutingLayout">
-      <TextView
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-              android:text="@string/audio_routingnotification_playHeader"/>
-
-      <TextView
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:id="@+id/audio_routingnotification_audioTrack_change"/>
-
-      <LinearLayout
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:orientation="horizontal">
-          <Button
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/audio_routingnotification_playBtn"
-              android:text="@string/audio_routingnotification_playBtn"/>
-
-          <Button
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:id="@+id/audio_routingnotification_playStopBtn"
-              android:text="@string/audio_routingnotification_playStopBtn"/>
-      </LinearLayout>
-    </LinearLayout>
+      android:text="@string/audio_input_routingnotification_instructions" />
 
   <LinearLayout
       android:layout_width="match_parent"
@@ -96,4 +95,5 @@
 
   <include layout="@layout/pass_fail_buttons" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_activity.xml b/apps/CtsVerifier/res/layout/audio_loopback_activity.xml
index 626ac4f..815f2bc 100644
--- a/apps/CtsVerifier/res/layout/audio_loopback_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_loopback_activity.xml
@@ -13,71 +13,120 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:padding="10dip"
-        android:orientation="vertical">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="10dip"
+    android:orientation="vertical"
+>
 
-  <TextView
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:scrollbars="vertical"
-      android:gravity="bottom"
-      android:id="@+id/info_text"
-      android:text="@string/audio_loopback_instructions" />
-  <LinearLayout
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical">
-      <Button
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:id="@+id/audio_loopback_plug_ready_btn"
-          android:text="@string/audio_loopback_plug_ready_btn"/>
-
-    <LinearLayout
-        android:orientation="vertical"
+    <ScrollView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:id="@+id/audio_loopback_layout">
+        android:id="@+id/scrollView"
+    >
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/audio_loopback_instructions2"
-            android:id="@+id/audio_loopback_instructions2"/>
-
-        <SeekBar
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:id="@+id/audio_loopback_level_seekbar"/>
+            android:orientation="vertical"
+        >
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/audio_loopback_level_text"
-            android:id="@+id/audio_loopback_level_text"/>
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:scrollbars="vertical"
+                android:gravity="bottom"
+                android:id="@+id/audio_general_headset_port_exists"
+                android:text="@string/audio_general_headset_port_exists" />
 
-        <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/audio_loopback_test_btn"
-            android:id="@+id/audio_loopback_test_btn"/>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+            >
 
-        <ProgressBar
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/audio_loopback_progress_bar"/>
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_general_headset_no"
+                    android:text="@string/audio_general_headset_no" />
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/audio_loopback_results_text"
-            android:id="@+id/audio_loopback_results_text"/>
-    </LinearLayout>
-    </LinearLayout>
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_general_headset_yes"
+                    android:text="@string/audio_general_headset_yes" />
 
-  <include layout="@layout/pass_fail_buttons" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/audio_loopback_headset_port"
+            >
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:id="@+id/info_text"
+                    android:text="@string/audio_loopback_instructions" />
+
+                <Button
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/audio_loopback_plug_ready_btn"
+                    android:text="@string/audio_loopback_plug_ready_btn" />
+
+                <LinearLayout
+                    android:orientation="vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:id="@+id/audio_loopback_layout"
+                >
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/audio_loopback_instructions2"
+                        android:id="@+id/audio_loopback_instructions2" />
+
+                    <SeekBar
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:id="@+id/audio_loopback_level_seekbar" />
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/audio_loopback_level_text"
+                        android:id="@+id/audio_loopback_level_text" />
+
+                    <Button
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/audio_loopback_test_btn"
+                        android:id="@+id/audio_loopback_test_btn" />
+
+                    <ProgressBar
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:id="@+id/audio_loopback_progress_bar" />
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/audio_loopback_results_text"
+                        android:id="@+id/audio_loopback_results_text" />
+                </LinearLayout>
+
+            </LinearLayout>
+            <include layout="@layout/pass_fail_buttons" />
+        </LinearLayout>
+    </ScrollView>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml b/apps/CtsVerifier/res/layout/audio_output_routingnotifications_test.xml
similarity index 61%
rename from apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
rename to apps/CtsVerifier/res/layout/audio_output_routingnotifications_test.xml
index cef30d6..d039691 100644
--- a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
+++ b/apps/CtsVerifier/res/layout/audio_output_routingnotifications_test.xml
@@ -14,19 +14,52 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/scrollView"
+    >
+
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:padding="10dip"
+        android:padding="20dp"
         android:orientation="vertical">
 
-  <TextView
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbars="vertical"
+            android:gravity="bottom"
+            android:id="@+id/audio_general_headset_port_exists"
+            android:text="@string/audio_general_headset_port_exists" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_general_headset_no"
+                android:text="@string/audio_general_headset_no" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_general_headset_yes"
+                android:text="@string/audio_general_headset_yes" />
+
+        </LinearLayout>
+
+    <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:scrollbars="vertical"
       android:gravity="bottom"
       android:id="@+id/info_text"
-      android:text="@string/audio_dev_routingnotification_instructions" />
+      android:text="@string/audio_output_routingnotification_instructions" />
 
   <LinearLayout
       android:layout_width="match_parent"
@@ -61,39 +94,7 @@
       </LinearLayout>
     </LinearLayout>
 
-  <LinearLayout
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical"
-      android:id="@+id/audioRecordRoutingLayout">
-      <TextView
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-              android:text="@string/audio_routingnotification_recHeader"/>
-
-      <TextView
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:id="@+id/audio_routingnotification_audioRecord_change"/>
-
-      <LinearLayout
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:orientation="horizontal">
-          <Button
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/audio_routingnotification_recordBtn"
-              android:text="@string/audio_routingnotification_recBtn"/>
-
-          <Button
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:id="@+id/audio_routingnotification_recordStopBtn"
-              android:text="@string/audio_routingnotification_recStopBtn"/>
-      </LinearLayout>
-    </LinearLayout>
-
   <include layout="@layout/pass_fail_buttons" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/keychain_main.xml b/apps/CtsVerifier/res/layout/keychain_main.xml
index 01eb255..3f695cd 100644
--- a/apps/CtsVerifier/res/layout/keychain_main.xml
+++ b/apps/CtsVerifier/res/layout/keychain_main.xml
@@ -24,22 +24,36 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
-        android:padding="10dip" >
+        android:padding="10dip">
 
-        <TextView
-            android:id="@+id/test_instruction"
-            style="@style/InstructionsFont"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="0" />
-
-        <TextView
-            android:id="@+id/test_log"
+        <ScrollView
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"
-            android:layout_gravity="bottom"
-            android:orientation="vertical" />
+            android:fillViewport="true">
+
+            <LinearLayout
+                android:id="@+id/test_messages"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <TextView
+                    android:id="@+id/test_instruction"
+                    style="@style/InstructionsFont"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0" />
+
+                <TextView
+                    android:id="@+id/test_log"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_weight="1"
+                    android:orientation="vertical" />
+
+            </LinearLayout>
+        </ScrollView>
 
         <LinearLayout
             android:id="@+id/action_buttons"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 77566a3..d8a96eb 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1277,7 +1277,25 @@
     <string name="provisioning_byod_no_video_capture_resolver">No video capture app present. Skip test.</string>
     <string name="provisioning_byod_no_audio_capture_resolver">No audio capture app present. Skip test.</string>
     <string name="provisioning_byod_capture_media_error">Error while capturing media from managed profile.</string>
+    <string name="provisioning_byod_capture_image_error">Error while capturing image from managed profile.</string>
 
+    <string name="provisioning_byod_auth_bound_key">Autentication-boud keys</string>
+    <string name="provisioning_byod_auth_bound_key_info">
+        This test verifies keystore cryptographic keys can be bound to device credentials.
+        These keys should only be available if there was a recent enough authentication.
+    </string>
+    <string name="provisioning_byod_auth_bound_key_instruction">
+        This test verifies keystore cryptographic keys can be bound to device lockscreen challenge or fingerprints (if available).
+        These keys should only be available if there was a recent enough authentication. \n
+
+        1. Press "Set up" to open Security settings. Create a lockscreen password and if available, enroll a fingerprint.\n
+        2. Go through the list of tests.\n
+        3. Mark the overall test pass or fail.\n
+        4. Once the set of tests are completed, remove the lockscreen challenge.
+    </string>
+    <string name="provisioning_byod_auth_bound_key_set_up">Set up</string>
+    <string name="provisioning_byod_lockscreen_bound_key">Lockscreen-bound key test</string>
+    <string name="provisioning_byod_fingerprint_bound_key">Fingerprint-bound key test</string>
     <!-- Strings for DeskClock -->
     <string name="deskclock_tests">Alarms and Timers Tests</string>
     <string name="deskclock_tests_info">
@@ -1436,12 +1454,13 @@
     <string name="provisioning_byod_profile_visible">Profile-aware accounts settings</string>
     <string name="provisioning_byod_admin_visible">Profile-aware device administrator settings</string>
     <string name="provisioning_byod_workapps_visible">Badged work apps visible in Launcher</string>
-    <string name="provisioning_byod_cross_profile">Open app cross profiles</string>
-    <string name="provisioning_byod_cross_profile_app_personal">
-        You selected the CTS Verifier option.
-    </string>
+    <string name="provisioning_byod_cross_profile_from_personal">Open app cross profiles from the personal side</string>
+    <string name="provisioning_byod_cross_profile_from_work">Open app cross profiles from the work side</string>
+    <string name="provisioning_app_linking">App links from the work side</string>
+    <string name="provisioning_byod_cross_profile_app_personal">You selected the personal option.</string>
     <string name="provisioning_byod_cross_profile_app_work">You selected the Work option.</string>
-    <string name="provisioning_byod_cross_profile_instruction">
+    <string name="provisioning_byod_cross_profile_app_ctsverifier"> You selected the ctsverifier option </string>
+    <string name="provisioning_byod_cross_profile_from_personal_instruction">
         Please press the Go button to start an action.\n
         \n
         You should be asked to choose either \"CTS Verifier\" or \"Work\" to complete the action.
@@ -1449,6 +1468,25 @@
         \n
         Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
     </string>
+    <string name="provisioning_byod_cross_profile_from_work_instruction">
+        Please press the Go button to start an action.\n
+        \n
+        You should be asked to choose either \"CTS Verifier\" or \"Personal\" to complete the action.
+        Pressing either should bring up a page stating your choice.\n
+        \n
+        Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+    </string>
+    <string name="provisioning_byod_app_linking_instruction">
+        Please press the Go button to start an action.\n
+        \n
+        You should be asked to choose either \"CTS Verifier\" or \"Personal\" to complete the action.\n
+        - If you choose \"CTS Verifier\", you should see a page stating your chose \"CTS Verifier\".\n
+        - If you choose \"Personal\", you should be presented with another dialog between \"CTS Verifier\"
+        and some other apps. In this case, you should choose \"CTS verifier\".\n
+        You should then see a page stating you chose \"Personal\".\n
+        \n
+        Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+    </string>
     <string name="provisioning_byod_keyguard_disabled_features">Keyguard disabled features</string>
     <string name="provisioning_byod_keyguard_disabled_features_info">
         This test exercises Keyguard Disabled Features. Follow instructions above.
@@ -1640,6 +1678,7 @@
     <string name="provisioning_byod_send_share_intent">Send share intent</string>
     <string name="provisioning_byod_cannot_resolve_beam_activity">Cannot find beam activity</string>
 
+    <string name="test_failed_cannot_start_intent">Cannot start the given intent.</string>
     <string name="provisioning_byod_no_activity">Cannot communicate with activity in the work profile.</string>
     <string name="provisioning_byod_delete_profile">Initiate deletion of work profile.</string>
     <string name="provisioning_byod_profile_deleted">Work profile deleted.</string>
@@ -1875,7 +1914,6 @@
     Do you see the programs named \"Dummy Program\" and their descriptions
     "Dummy Program Description" in the EPG?
     </string>
-    <string name="tv_input_discover_test_yes">Yes</string>
 
     <string name="tv_parental_control_test">TV app parental controls test</string>
     <string name="tv_parental_control_test_info">
@@ -1964,6 +2002,24 @@
     The playback position should be moved to the next position.
     </string>
 
+    <string name="tv_app_link_test">TV app app-link test</string>
+    <string name="tv_app_link_test_info">
+    Verify that the bundled TV app supports linking to channel apps. If TV input service provides
+    links for its specific channels, TV app should show the links in a proper format.
+    </string>
+    <string name="tv_app_link_test_select_app_link">
+    Select the \"Launch TV app\" button, then check if you can see a menu with \"Cts App-Link Text\"
+    text in red background. If you see the link, select it to follow the link.
+    </string>
+    <string name="tv_app_link_test_verify_link_clicked">
+    The app-link must have been clicked and the activity should be changed correctly.
+    </string>
+    <string name="tv_input_link_test_verify_link_interface">
+    Do you see the app-link card similar to the image on the left?\n
+    1) You should see the poster art image, but the color could be differ.\n
+    2) You should see the text \"Cts App-Link Text\".\n
+    </string>
+
     <string name="overlay_view_text">Overlay View Dummy Text</string>
     <string name="fake_rating">Fake</string>
 
@@ -1984,25 +2040,34 @@
     <string name="error_screen_pinning_did_not_exit">Screen was not unpinned.</string>
     <string name="error_screen_pinning_couldnt_exit">Could not exit screen pinning through API.</string>
 
-    <!--  Audio Devices Notifcations Test -->
-    <string name="audio_devices_notifications_test">Audio Devices Notifications Test</string>
-    <string name="audio_devices_notification_instructions">
+    <!--  Audio Devices Notifcations Tests -->
+    <string name="audio_out_devices_notifications_test">Audio Output Devices Notifications Test</string>
+    <string name="audio_out_devices_notification_instructions">
           Click the "Clear Messages" button then connect and disconnect a wired headset.
           Note if the appropriate notification messages appear below.
     </string>
+    <string name="audio_in_devices_notifications_test">Audio Input Devices Notifications Test</string>
+    <string name="audio_in_devices_notification_instructions">
+          Click the "Clear Messages" button then connect and disconnect a microphone or wired headset.
+          Note if the appropriate notification messages appear below.
+    </string>
     <string name="audio_dev_notification_clearmsgs">Clear Messages</string>
     <string name="audio_dev_notification_connectMsg">CONNECT DETECTED</string>
     <string name="audio_dev_notification_disconnectMsg">DISCONNECT DETECTED</string>
 
-    <!--  Audio Routing Notifcations Test -->
-    <string name="audio_routingnotifications_test">Audio Routing Notifications Test</string>
-    <string name="audio_dev_routingnotification_instructions">
-          Click on the "Play" button in the AudioTrack Routing Notifictions section below to
+    <string name="audio_input_routingnotifications_test">Audio Input Routing Notifications Test</string>
+    <string name="audio_input_routingnotification_instructions">
+          Click on the "Record" button in the AudioRecord Routing Notifications section below to
+          start recording. Insert a wired headset or microphone. Observe a message acknowledging the
+          rerouting event below. Remove the wired headset and observe the new routing message.
+          Click on the "Stop" button to stop recording.\n
+    </string>
+    <string name="audio_output_routingnotifications_test">Audio Output Routing Notifications Test</string>
+    <string name="audio_output_routingnotification_instructions">
+          Click on the "Play" button in the AudioTrack Routing Notifications section below to
           start (silent) playback. Insert a wired headset. Observe a message acknowledging the
           rerouting event below. Remove the wired headset and observe the new routing message.
           Click on the "Stop" button to stop playback.\n
-          Repeat the process with "Record" and "Stop" button in the AudioRecord Routing
-          Notifications section below.
     </string>
     <string name="audio_routingnotification_playBtn">Play</string>
     <string name="audio_routingnotification_playStopBtn">Stop</string>
@@ -2013,14 +2078,19 @@
     <string name="audio_routingnotification_trackRoutingMsg">AudioTrack rerouting</string>
     <string name="audio_routingnotification_recordRoutingMsg">AudioRecord rerouting</string>
 
+    <!-- Audio general text -->
+    <string name="audio_general_headset_port_exists">Does this device have a headset port?</string>
+    <string name="audio_general_headset_no">No</string>
+    <string name="audio_general_headset_yes">Yes</string>
+
     <!-- Audio Loopback Latency Test -->
     <string name="audio_loopback_test">Audio Loopback Latency Test</string>
      <string name="audio_loopback_info">
-          This test requires the Loopback Plug. Please connect a Loopback Plug on the headset
+          This test requires the Loopback Plug. Please connect a Loopback Plug into the headset
           connector, and proceed with the instructions on the screen.
           The system will measure the input-output audio latency by injecting a pulse on the output,
           and computing the distance between replicas of the pulse.
-          You can vary the Audio Level slider to ensure the pulse will feed back at adecuate levels.
+          You can vary the Audio Level slider to ensure the pulse will feed back at adequate levels.
           Repeat until a confidence level >= 0.6 is achieved.
     </string>
     <string name="audio_loopback_instructions">
@@ -2055,7 +2125,7 @@
     <string name="audio_frequency_speaker_test">Audio Frequency Speaker Test</string>
     <string name="audio_frequency_speaker_info">
         This test requires an external USB reference microphone. Please connect the USB microphone and proceed with the instructions on the screen.
-        The system will measure frequency response of the left and right speakers (if there are two speakers), or twice the response of the mono speaker.
+        The system will measure frequency response of the left and right speakers (if there are two speakers), or the response of the mono speaker twice.
        </string>
     <string name="audio_frequency_speaker_instructions">
           Please connect an USB reference microphone and press "USB Reference microphone ready"
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index 789effa..91b8d93 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -41,6 +42,7 @@
  * Instructions are shown on top of the screen and a test preparation button is provided.
  */
 public abstract class DialogTestListActivity extends PassFailButtons.TestListActivity {
+    private final String TAG = "DialogTestListActivity";
     private final int mLayoutId;
     private final int mTitleStringId;
     private final int mInfoStringId;
@@ -170,7 +172,13 @@
             mCurrentTestPosition = position;
             ((DialogTestListItem)test).performTest(this);
         } else {
-            super.handleItemClick(l, v, position, id);
+            try {
+                super.handleItemClick(l, v, position, id);
+            } catch (ActivityNotFoundException e) {
+                Log.d(TAG, "handleItemClick() threw exception: ", e);
+                setTestResult(test, TestResult.TEST_RESULT_FAILED);
+                showToast(R.string.test_failed_cannot_start_intent);
+            }
         }
     }
 
@@ -196,7 +204,7 @@
         // do nothing, override in subclass if needed
     }
 
-    protected void setTestResult(DialogTestListItem test, int result) {
+    protected void setTestResult(TestListAdapter.TestListItem test, int result) {
         // Bundle result in an intent to feed into handleLaunchTestResult
         Intent resultIntent = new Intent();
         TestResult.addResultData(resultIntent, result, test.testName, /* testDetails */ null,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
index d3e2571..508fae0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
@@ -64,6 +64,9 @@
     OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
     Context mContext;
 
+    Button mHeadsetPortYes;
+    Button mHeadsetPortNo;
+
     Button mLoopbackPlugReady;
     LinearLayout mLinearLayout;
     Button mTestButton;
@@ -116,6 +119,20 @@
                     Log.i(TAG, "audio loopback test");
                     startAudioTest();
                     break;
+                case R.id.audio_general_headset_yes:
+                    Log.i(TAG, "User confirms Headset Port existence");
+                    mLoopbackPlugReady.setEnabled(true);
+                    recordHeasetPortFound(true);
+                    mHeadsetPortYes.setEnabled(false);
+                    mHeadsetPortNo.setEnabled(false);
+                    break;
+                case R.id.audio_general_headset_no:
+                    Log.i(TAG, "User denies Headset Port existence");
+                    recordHeasetPortFound(false);
+                    getPassButton().setEnabled(true);
+                    mHeadsetPortYes.setEnabled(false);
+                    mHeadsetPortNo.setEnabled(false);
+                    break;
             }
         }
     }
@@ -127,8 +144,14 @@
 
         mContext = this;
 
+        mHeadsetPortYes = (Button)findViewById(R.id.audio_general_headset_yes);
+        mHeadsetPortYes.setOnClickListener(mBtnClickListener);
+        mHeadsetPortNo = (Button)findViewById(R.id.audio_general_headset_no);
+        mHeadsetPortNo.setOnClickListener(mBtnClickListener);
+
         mLoopbackPlugReady = (Button)findViewById(R.id.audio_frequency_line_plug_ready_btn);
         mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
+        mLoopbackPlugReady.setEnabled(false);
         mLinearLayout = (LinearLayout)findViewById(R.id.audio_frequency_line_layout);
         mTestButton = (Button)findViewById(R.id.audio_frequency_line_test_btn);
         mTestButton.setOnClickListener(mBtnClickListener);
@@ -479,6 +502,14 @@
         Log.v(TAG, "Results Recorded");
     }
 
+    private void recordHeasetPortFound(boolean found) {
+        getReportLog().addValue(
+                "User Reported Headset Port",
+                found ? 1.0 : 0,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+    }
+
     private void startRecording() {
         synchronized (mRecordingLock) {
             mIsRecording = true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
index b37a721..03d84e1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
@@ -72,6 +72,9 @@
     final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
     Context mContext;
 
+    Button mHeadsetPortYes;
+    Button mHeadsetPortNo;
+
     Button mSpeakersReady;              //user signal to have connected external speakers
     Button mTest1Button;                //execute test 1
     Button mUsbMicReady;          //user signal to have connected USB Microphone
@@ -137,6 +140,20 @@
             case R.id.audio_frequency_mic_test2_btn:
                 startTest2();
                 break;
+            case R.id.audio_general_headset_yes:
+                Log.i(TAG, "User confirms Headset Port existence");
+                mSpeakersReady.setEnabled(true);
+                recordHeasetPortFound(true);
+                mHeadsetPortYes.setEnabled(false);
+                mHeadsetPortNo.setEnabled(false);
+                break;
+            case R.id.audio_general_headset_no:
+                Log.i(TAG, "User denies Headset Port existence");
+                recordHeasetPortFound(false);
+                getPassButton().setEnabled(true);
+                mHeadsetPortYes.setEnabled(false);
+                mHeadsetPortNo.setEnabled(false);
+                break;
             }
         }
     }
@@ -146,10 +163,17 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.audio_frequency_mic_activity);
         mContext = this;
+
+        mHeadsetPortYes = (Button)findViewById(R.id.audio_general_headset_yes);
+        mHeadsetPortYes.setOnClickListener(mBtnClickListener);
+        mHeadsetPortNo = (Button)findViewById(R.id.audio_general_headset_no);
+        mHeadsetPortNo.setOnClickListener(mBtnClickListener);
+
         mSpeakerReadyText = (TextView) findViewById(R.id.audio_frequency_mic_speakers_ready_status);
 
         mSpeakersReady  = (Button)findViewById(R.id.audio_frequency_mic_speakers_ready_btn);
         mSpeakersReady.setOnClickListener(mBtnClickListener);
+        mSpeakersReady.setEnabled(false);
         mTest1Button = (Button)findViewById(R.id.audio_frequency_mic_test1_btn);
         mTest1Button.setOnClickListener(mBtnClickListener);
         mTest1Result = (TextView)findViewById(R.id.audio_frequency_mic_results1_text);
@@ -644,6 +668,14 @@
         Log.v(TAG, "Results Recorded");
     }
 
+    private void recordHeasetPortFound(boolean found) {
+        getReportLog().addValue(
+                "User Reported Headset Port",
+                found ? 1.0 : 0,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+    }
+
     private void startRecording() {
         synchronized (mRecordingLock) {
             mIsRecording = true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
similarity index 82%
copy from apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
index 93e0507..e253635 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.cts.verifier.audio;
 
-import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
 import android.content.Context;
@@ -34,10 +33,10 @@
 import android.widget.TextView;
 
 /**
- * Tests Audio Device Connection events by prompting the user to insert/remove a wired headset
- * and noting the presence (or absence) of notifictions.
+ * Tests Audio Device Connection events for output by prompting the user to insert/remove a
+ * wired headset (or microphone) and noting the presence (or absence) of notifications.
  */
-public class AudioDeviceNotificationsActivity extends PassFailButtons.Activity {
+public class AudioInputDeviceNotificationsActivity extends HeadsetHonorSystemActivity {
     Context mContext;
 
     TextView mConnectView;
@@ -62,6 +61,11 @@
     }
 
     @Override
+    protected void enableTestButtons(boolean enabled) {
+        // Nothing to do.
+    }
+
+    @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.audio_dev_notify);
@@ -71,6 +75,9 @@
         mConnectView = (TextView)findViewById(R.id.audio_dev_notification_connect_msg);
         mDisconnectView = (TextView)findViewById(R.id.audio_dev_notification_disconnect_msg);
 
+        ((TextView)findViewById(R.id.info_text)).setText(mContext.getResources().getString(
+                R.string.audio_in_devices_notification_instructions));
+
         mClearMsgsBtn = (Button)findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn);
         mClearMsgsBtn.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
@@ -82,6 +89,9 @@
         AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
         audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
 
+        // "Honor System" buttons
+        super.setup();
+
         setPassFailButtonClickListeners();
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
new file mode 100644
index 0000000..eefa9e4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Tests AudioRecord (re)Routing messages.
+ */
+public class AudioInputRoutingNotificationsActivity extends HeadsetHonorSystemActivity {
+    private static final String TAG = "AudioInputRoutingNotificationsActivity";
+
+    Button recordBtn;
+    Button stopBtn;
+
+    Context mContext;
+
+    int mNumRecordNotifications = 0;
+
+    OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+    TrivialRecorder mAudioRecorder = new TrivialRecorder();
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+                case R.id.audio_routingnotification_recordBtn:
+                    mAudioRecorder.start();
+                    break;
+
+                case R.id.audio_routingnotification_recordStopBtn:
+                    mAudioRecorder.stop();
+                    break;
+            }
+        }
+    }
+
+    private class AudioRecordRoutingChangeListener implements AudioRecord.OnRoutingChangedListener {
+        public void onRoutingChanged(AudioRecord audioRecord) {
+            mNumRecordNotifications++;
+            TextView textView =
+                    (TextView)findViewById(R.id.audio_routingnotification_audioRecord_change);
+            String msg = mContext.getResources().getString(
+                    R.string.audio_routingnotification_recordRoutingMsg);
+            AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
+            CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
+            int deviceType = routedDevice != null ? routedDevice.getType() : -1;
+            textView.setText(msg + " - " +
+                             deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
+                             " - " + mNumRecordNotifications);
+        }
+    }
+
+    protected void enableTestButtons(boolean enabled) {
+        recordBtn.setEnabled(enabled);
+        stopBtn.setEnabled(enabled);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_input_routingnotifications_test);
+
+        Button btn;
+        recordBtn = (Button)findViewById(R.id.audio_routingnotification_recordBtn);
+        recordBtn.setOnClickListener(mBtnClickListener);
+        stopBtn = (Button)findViewById(R.id.audio_routingnotification_recordStopBtn);
+        stopBtn.setOnClickListener(mBtnClickListener);
+
+        mContext = this;
+
+        AudioRecord audioRecord = mAudioRecorder.getAudioRecord();
+        audioRecord.addOnRoutingChangedListener(
+            new AudioRecordRoutingChangeListener(), new Handler());
+
+        // "Honor System" buttons
+        super.setup();
+
+        setPassFailButtonClickListeners();
+    }
+
+    @Override
+    public void onBackPressed () {
+        mAudioRecorder.shutDown();
+        super.onBackPressed();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
index e603a69..fbec57a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
@@ -61,6 +61,9 @@
     OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
     Context mContext;
 
+    Button mHeadsetPortYes;
+    Button mHeadsetPortNo;
+
     Button mLoopbackPlugReady;
     TextView mAudioLevelText;
     SeekBar mAudioLevelSeekbar;
@@ -83,7 +86,20 @@
                     Log.i(TAG, "audio loopback test");
                     startAudioTest();
                     break;
-
+                case R.id.audio_general_headset_yes:
+                    Log.i(TAG, "User confirms Headset Port existence");
+                    mLoopbackPlugReady.setEnabled(true);
+                    recordHeasetPortFound(true);
+                    mHeadsetPortYes.setEnabled(false);
+                    mHeadsetPortNo.setEnabled(false);
+                    break;
+                case R.id.audio_general_headset_no:
+                    Log.i(TAG, "User denies Headset Port existence");
+                    recordHeasetPortFound(false);
+                    getPassButton().setEnabled(true);
+                    mHeadsetPortYes.setEnabled(false);
+                    mHeadsetPortNo.setEnabled(false);
+                    break;
             }
         }
     }
@@ -95,8 +111,14 @@
 
         mContext = this;
 
+        mHeadsetPortYes = (Button)findViewById(R.id.audio_general_headset_yes);
+        mHeadsetPortYes.setOnClickListener(mBtnClickListener);
+        mHeadsetPortNo = (Button)findViewById(R.id.audio_general_headset_no);
+        mHeadsetPortNo.setOnClickListener(mBtnClickListener);
+
         mLoopbackPlugReady = (Button)findViewById(R.id.audio_loopback_plug_ready_btn);
         mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
+        mLoopbackPlugReady.setEnabled(false);
         mLinearLayout = (LinearLayout)findViewById(R.id.audio_loopback_layout);
         mAudioLevelText = (TextView)findViewById(R.id.audio_loopback_level_text);
         mAudioLevelSeekbar = (SeekBar)findViewById(R.id.audio_loopback_level_seekbar);
@@ -135,7 +157,7 @@
 
         setPassFailButtonClickListeners();
         getPassButton().setEnabled(false);
-        setInfoResources(R.string.sample_test, R.string.audio_loopback_info, -1);
+        setInfoResources(R.string.audio_loopback_test, R.string.audio_loopback_info, -1);
     }
 
     /**
@@ -304,4 +326,12 @@
 
         Log.v(TAG,"Results Recorded");
     }
+
+    private void recordHeasetPortFound(boolean found) {
+        getReportLog().addValue(
+                "User Reported Headset Port",
+                found ? 1.0 : 0,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
similarity index 82%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
index 93e0507..ad8ba68 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.cts.verifier.audio;
 
-import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
 import android.content.Context;
@@ -34,10 +33,10 @@
 import android.widget.TextView;
 
 /**
- * Tests Audio Device Connection events by prompting the user to insert/remove a wired headset
- * and noting the presence (or absence) of notifictions.
+ * Tests Audio Device Connection events for output devices by prompting the user to
+ * insert/remove a wired headset and noting the presence (or absence) of notifications.
  */
-public class AudioDeviceNotificationsActivity extends PassFailButtons.Activity {
+public class AudioOutputDeviceNotificationsActivity extends HeadsetHonorSystemActivity {
     Context mContext;
 
     TextView mConnectView;
@@ -62,6 +61,11 @@
     }
 
     @Override
+    protected void enableTestButtons(boolean enabled) {
+        // Nothing to do.
+    }
+
+    @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.audio_dev_notify);
@@ -71,6 +75,9 @@
         mConnectView = (TextView)findViewById(R.id.audio_dev_notification_connect_msg);
         mDisconnectView = (TextView)findViewById(R.id.audio_dev_notification_disconnect_msg);
 
+        ((TextView)findViewById(R.id.info_text)).setText(mContext.getResources().getString(
+                R.string.audio_out_devices_notification_instructions));
+
         mClearMsgsBtn = (Button)findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn);
         mClearMsgsBtn.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
@@ -82,6 +89,9 @@
         AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
         audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
 
+        // "Honor System" buttons
+        super.setup();
+
         setPassFailButtonClickListeners();
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
new file mode 100644
index 0000000..a6d8846
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Tests AudioTrack and AudioRecord (re)Routing messages.
+ */
+public class AudioOutputRoutingNotificationsActivity extends HeadsetHonorSystemActivity {
+    private static final String TAG = "AudioOutputRoutingNotificationsActivity";
+
+    Context mContext;
+
+    Button playBtn;
+    Button stopBtn;
+
+    private OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+    int mNumTrackNotifications = 0;
+
+    TrivialPlayer mAudioPlayer = new TrivialPlayer();
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+                case R.id.audio_routingnotification_playBtn:
+                    mAudioPlayer.start();
+                    break;
+
+                case R.id.audio_routingnotification_playStopBtn:
+                    mAudioPlayer.stop();
+                    break;
+            }
+        }
+    }
+
+    private class AudioTrackRoutingChangeListener implements AudioTrack.OnRoutingChangedListener {
+        public void onRoutingChanged(AudioTrack audioTrack) {
+            mNumTrackNotifications++;
+            TextView textView =
+                (TextView)findViewById(R.id.audio_routingnotification_audioTrack_change);
+            String msg = mContext.getResources().getString(
+                    R.string.audio_routingnotification_trackRoutingMsg);
+            AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
+            CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
+            int deviceType = routedDevice != null ? routedDevice.getType() : -1;
+            textView.setText(msg + " - " +
+                             deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
+                             " - " + mNumTrackNotifications);
+        }
+    }
+
+    @Override
+    protected void enableTestButtons(boolean enabled) {
+        playBtn.setEnabled(enabled);
+        stopBtn.setEnabled(enabled);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_output_routingnotifications_test);
+
+        mContext = this;
+
+        playBtn = (Button)findViewById(R.id.audio_routingnotification_playBtn);
+        playBtn.setOnClickListener(mBtnClickListener);
+        stopBtn = (Button)findViewById(R.id.audio_routingnotification_playStopBtn);
+        stopBtn.setOnClickListener(mBtnClickListener);
+
+        AudioTrack audioTrack = mAudioPlayer.getAudioTrack();
+        audioTrack.addOnRoutingChangedListener(
+            new AudioTrackRoutingChangeListener(), new Handler());
+
+        // "Honor System" buttons
+        super.setup();
+
+        setPassFailButtonClickListeners();
+    }
+
+    @Override
+    public void onBackPressed () {
+        mAudioPlayer.shutDown();
+        super.onBackPressed();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java
deleted file mode 100644
index b6a4255..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.audio;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.Context;
-
-import android.media.AudioDeviceCallback;
-import android.media.AudioDeviceInfo;
-import android.media.AudioManager;
-import android.media.AudioRecord;
-import android.media.AudioTrack;
-
-import android.os.Bundle;
-import android.os.Handler;
-
-import android.util.Log;
-
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Tests AudioTrack and AudioRecord (re)Routing messages.
- */
-public class AudioRoutingNotificationsActivity extends PassFailButtons.Activity {
-    private static final String TAG = "AudioRoutingNotificationsActivity";
-
-    Context mContext;
-
-    OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
-
-    int mNumTrackNotifications = 0;
-    int mNumRecordNotifications = 0;
-
-    TrivialPlayer mAudioPlayer = new TrivialPlayer();
-    TrivialRecorder mAudioRecorder = new TrivialRecorder();
-
-    private class OnBtnClickListener implements OnClickListener {
-        @Override
-        public void onClick(View v) {
-            switch (v.getId()) {
-                case R.id.audio_routingnotification_playBtn:
-                    Log.i(TAG, "audio_routingnotification_playBtn");
-                    mAudioPlayer.start();
-                    break;
-
-                case R.id.audio_routingnotification_playStopBtn:
-                    Log.i(TAG, "audio_routingnotification_playStopBtn");
-                    mAudioPlayer.stop();
-                    break;
-
-                case R.id.audio_routingnotification_recordBtn:
-                    break;
-
-                case R.id.audio_routingnotification_recordStopBtn:
-                    break;
-            }
-        }
-    }
-
-    private class AudioTrackRoutingChangeListener implements AudioTrack.OnRoutingChangedListener {
-        public void onRoutingChanged(AudioTrack audioTrack) {
-            mNumTrackNotifications++;
-            TextView textView =
-                (TextView)findViewById(R.id.audio_routingnotification_audioTrack_change);
-            String msg = mContext.getResources().getString(
-                    R.string.audio_routingnotification_trackRoutingMsg);
-            AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
-            CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
-            int deviceType = routedDevice != null ? routedDevice.getType() : -1;
-            textView.setText(msg + " - " +
-                             deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
-                             " - " + mNumTrackNotifications);
-        }
-    }
-
-    private class AudioRecordRoutingChangeListener implements AudioRecord.OnRoutingChangedListener {
-        public void onRoutingChanged(AudioRecord audioRecord) {
-            mNumRecordNotifications++;
-            TextView textView =
-                    (TextView)findViewById(R.id.audio_routingnotification_audioRecord_change);
-            String msg = mContext.getResources().getString(
-                    R.string.audio_routingnotification_recordRoutingMsg);
-            AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
-            CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
-            int deviceType = routedDevice != null ? routedDevice.getType() : -1;
-            textView.setText(msg + " - " +
-                             deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
-                             " - " + mNumRecordNotifications);
-        }
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.audio_routingnotifications_test);
-
-        Button btn;
-        btn = (Button)findViewById(R.id.audio_routingnotification_playBtn);
-        btn.setOnClickListener(mBtnClickListener);
-        btn = (Button)findViewById(R.id.audio_routingnotification_playStopBtn);
-        btn.setOnClickListener(mBtnClickListener);
-        btn = (Button)findViewById(R.id.audio_routingnotification_recordBtn);
-        btn.setOnClickListener(mBtnClickListener);
-        btn = (Button)findViewById(R.id.audio_routingnotification_recordStopBtn);
-        btn.setOnClickListener(mBtnClickListener);
-
-        mContext = this;
-
-        AudioTrack audioTrack = mAudioPlayer.getAudioTrack();
-        audioTrack.addOnRoutingChangedListener(
-            new AudioTrackRoutingChangeListener(), new Handler());
-
-        AudioRecord audioRecord = mAudioRecorder.getAudioRecord();
-        audioRecord.addOnRoutingChangedListener(
-            new AudioRecordRoutingChangeListener(), new Handler());
-
-        setPassFailButtonClickListeners();
-    }
-
-    @Override
-    public void onBackPressed () {
-        mAudioPlayer.shutDown();
-        mAudioRecorder.shutDown();
-        super.onBackPressed();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HeadsetHonorSystemActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HeadsetHonorSystemActivity.java
new file mode 100644
index 0000000..a82b994
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HeadsetHonorSystemActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import android.content.Context;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+//import android.widget.TextView;
+
+abstract class HeadsetHonorSystemActivity extends PassFailButtons.Activity {
+    private static final String TAG = "HeadsetHonorSystemActivity";
+
+    private OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+    abstract protected void enableTestButtons(boolean enabled);
+
+    private void recordHeadsetPortFound(boolean found) {
+        getReportLog().addValue(
+                "User Reported Headset Port",
+                found ? 1.0 : 0,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+    }
+
+    protected void setup() {
+        // The "Honor" system buttons
+        ((Button)findViewById(R.id.audio_general_headset_no)).
+            setOnClickListener(mBtnClickListener);
+        ((Button)findViewById(R.id.audio_general_headset_yes)).
+            setOnClickListener(mBtnClickListener);
+
+        enableTestButtons(false);
+    }
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+                case R.id.audio_general_headset_no:
+                    Log.i(TAG, "User denies Headset Port existence");
+                    enableTestButtons(false);
+                    recordHeadsetPortFound(false);
+                    break;
+
+                case R.id.audio_general_headset_yes:
+                    Log.i(TAG, "User confirms Headset Port existence");
+                    enableTestButtons(true);
+                    recordHeadsetPortFound(true);
+                    break;
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 27f8c28..e3ff74b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -39,12 +39,14 @@
 import android.media.Image;
 import android.media.ImageReader;
 import android.media.ImageWriter;
+import android.media.Image.Plane;
 import android.net.Uri;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.SystemClock;
 import android.os.Vibrator;
 import android.util.Log;
 import android.util.Rational;
@@ -56,6 +58,8 @@
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 
+import com.android.cts.verifier.camera.its.StatsImage;
+
 import org.json.JSONArray;
 import org.json.JSONObject;
 
@@ -70,6 +74,8 @@
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
 import java.nio.charset.Charset;
 import java.security.MessageDigest;
 import java.util.ArrayList;
@@ -154,6 +160,9 @@
     private AtomicInteger mCountYuv = new AtomicInteger();
     private AtomicInteger mCountCapRes = new AtomicInteger();
     private boolean mCaptureRawIsDng;
+    private boolean mCaptureRawIsStats;
+    private int mCaptureStatsGridWidth;
+    private int mCaptureStatsGridHeight;
     private CaptureResult mCaptureResults[] = null;
 
     private volatile ConditionVariable mInterlock3A = new ConditionVariable(true);
@@ -404,7 +413,7 @@
                             continue;
                         }
                         if (b.hasArray()) {
-                            mOpenSocket.getOutputStream().write(b.array());
+                            mOpenSocket.getOutputStream().write(b.array(), 0, b.capacity());
                         } else {
                             byte[] barray = new byte[b.capacity()];
                             b.get(barray);
@@ -665,7 +674,16 @@
                     jsonSurface.put("height", readers[i].getHeight());
                     int format = readers[i].getImageFormat();
                     if (format == ImageFormat.RAW_SENSOR) {
-                        jsonSurface.put("format", "raw");
+                        if (mCaptureRawIsStats) {
+                            jsonSurface.put("format", "rawStats");
+                            jsonSurface.put("width", readers[i].getWidth()/mCaptureStatsGridWidth);
+                            jsonSurface.put("height",
+                                    readers[i].getHeight()/mCaptureStatsGridHeight);
+                        } else if (mCaptureRawIsDng) {
+                            jsonSurface.put("format", "dng");
+                        } else {
+                            jsonSurface.put("format", "raw");
+                        }
                     } else if (format == ImageFormat.RAW10) {
                         jsonSurface.put("format", "raw10");
                     } else if (format == ImageFormat.RAW12) {
@@ -1068,6 +1086,12 @@
                         outputFormats[i] = ImageFormat.RAW_SENSOR;
                         sizes = ItsUtils.getRaw16OutputSizes(mCameraCharacteristics);
                         mCaptureRawIsDng = true;
+                    } else if ("rawStats".equals(sformat)) {
+                        outputFormats[i] = ImageFormat.RAW_SENSOR;
+                        sizes = ItsUtils.getRaw16OutputSizes(mCameraCharacteristics);
+                        mCaptureRawIsStats = true;
+                        mCaptureStatsGridWidth = surfaceObj.optInt("gridWidth");
+                        mCaptureStatsGridHeight = surfaceObj.optInt("gridHeight");
                     } else {
                         throw new ItsException("Unsupported format: " + sformat);
                     }
@@ -1086,6 +1110,14 @@
                     if (height <= 0) {
                         height = ItsUtils.getMaxSize(sizes).getHeight();
                     }
+                    if (mCaptureStatsGridWidth <= 0) {
+                        mCaptureStatsGridWidth = width;
+                    }
+                    if (mCaptureStatsGridHeight <= 0) {
+                        mCaptureStatsGridHeight = height;
+                    }
+
+                    // TODO: Crop to the active array in the stats image analysis.
 
                     outputSizes[i] = new Size(width, height);
                 }
@@ -1122,6 +1154,7 @@
                 mCountRaw12.set(0);
                 mCountCapRes.set(0);
                 mCaptureRawIsDng = false;
+                mCaptureRawIsStats = false;
                 mCaptureResults = new CaptureResult[requests.size()];
 
                 JSONArray jsonOutputSpecs = ItsUtils.getOutputSpecs(params);
@@ -1235,6 +1268,7 @@
         mCountRaw12.set(0);
         mCountCapRes.set(0);
         mCaptureRawIsDng = false;
+        mCaptureRawIsStats = false;
 
         try {
             // Parse the JSON to get the list of capture requests.
@@ -1427,8 +1461,28 @@
                     int count = mCountRawOrDng.getAndIncrement();
                     if (! mCaptureRawIsDng) {
                         byte[] img = ItsUtils.getDataFromImage(capture);
-                        ByteBuffer buf = ByteBuffer.wrap(img);
-                        mSocketRunnableObj.sendResponseCaptureBuffer("rawImage", buf);
+                        if (! mCaptureRawIsStats) {
+                            ByteBuffer buf = ByteBuffer.wrap(img);
+                            mSocketRunnableObj.sendResponseCaptureBuffer("rawImage", buf);
+                        } else {
+                            // Compute the requested stats on the raw frame, and return the results
+                            // in a new "stats image".
+                            long startTimeMs = SystemClock.elapsedRealtime();
+                            int w = capture.getWidth();
+                            int h = capture.getHeight();
+                            int gw = mCaptureStatsGridWidth;
+                            int gh = mCaptureStatsGridHeight;
+                            float[] stats = StatsImage.computeStatsImage(img, w, h, gw, gh);
+                            long endTimeMs = SystemClock.elapsedRealtime();
+                            Log.e(TAG, "Raw stats computation takes " + (endTimeMs - startTimeMs) + " ms");
+
+                            ByteBuffer bBuf = ByteBuffer.allocateDirect(stats.length * 4);
+                            bBuf.order(ByteOrder.nativeOrder());
+                            FloatBuffer fBuf = bBuf.asFloatBuffer();
+                            fBuf.put(stats);
+                            fBuf.position(0);
+                            mSocketRunnableObj.sendResponseCaptureBuffer("rawStatsImage", bBuf);
+                        }
                     } else {
                         // Wait until the corresponding capture result is ready, up to a timeout.
                         long t0 = android.os.SystemClock.elapsedRealtime();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/StatsImage.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/StatsImage.java
new file mode 100644
index 0000000..037177c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/StatsImage.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.camera.its;
+
+import android.util.Log;
+
+public class StatsImage {
+
+    static {
+        try {
+            System.loadLibrary("ctsverifier_jni");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e("StatsImage", "Error loading cts verifier JNI library");
+            e.printStackTrace();
+        }
+    }
+
+    public native static float[] computeStatsImage(
+            byte[] img, int width, int height, int gridW, int gridH);
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 51e0a62..3c108da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -232,6 +232,7 @@
 
     public static final Feature[] ALL_MNC_FEATURES = {
             new Feature(PackageManager.FEATURE_MIDI, false),
+            new Feature(PackageManager.FEATURE_AUDIO_PRO, false),
     };
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java
new file mode 100644
index 0000000..073412d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java
@@ -0,0 +1,381 @@
+package com.android.cts.verifier.managedprovisioning;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.KeyguardManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.CountDownTimer;
+import android.provider.Settings;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.UserNotAuthenticatedException;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestResult;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+/**
+ * Test device credential-bound keys in work profile.
+ * Currently there are two types, one is keys bound to lockscreen passwords which can be configured
+ * to remain available within a certain timeout after the latest successful user authentication.
+ * The other is keys bound to fingerprint authentication which require explicit fingerprint
+ * authentication before they can be accessed.
+ */
+public class AuthenticationBoundKeyTestActivity extends DialogTestListActivity {
+
+    public static final String ACTION_AUTH_BOUND_KEY_TEST =
+            "com.android.cts.verifier.managedprovisioning.action.AUTH_BOUND_KEY_TEST";
+
+    private static final int AUTHENTICATION_DURATION_SECONDS = 5;
+    private static final String LOCKSCREEN_KEY_NAME = "mp_lockscreen_key";
+    private static final String FINGERPRINT_KEY_NAME = "mp_fingerprint_key";
+    private static final byte[] SECRET_BYTE_ARRAY = new byte[] {1, 2, 3, 4, 5, 6};
+    private static final int CONFIRM_CREDENTIALS_REQUEST_CODE = 1;
+    private static final int FINGERPRINT_PERMISSION_REQUEST_CODE = 0;
+
+    private static final int LOCKSCREEN = 1;
+    private static final int FINGERPRINT = 2;
+
+    private static final String KEYSTORE_NAME = "AndroidKeyStore";
+    private static final String CIPHER_TRANSFORMATION =  KeyProperties.KEY_ALGORITHM_AES + "/"
+            + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7;
+
+
+    private KeyguardManager mKeyguardManager;
+    private FingerprintManager mFingerprintManager;
+    private boolean mFingerprintSupported;
+
+    private DialogTestListItem mLockScreenBoundKeyTest;
+    private DialogTestListItem mFingerprintBoundKeyTest;
+
+    private Cipher mFingerprintCipher;
+
+    public AuthenticationBoundKeyTestActivity() {
+        super(R.layout.provisioning_byod,
+                R.string.provisioning_byod_auth_bound_key,
+                R.string.provisioning_byod_auth_bound_key_info,
+                R.string.provisioning_byod_auth_bound_key_instruction);
+    }
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
+        mFingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
+        mFingerprintSupported = mFingerprintManager != null
+                && mFingerprintManager.isHardwareDetected();
+        // Need to have valid mFingerprintSupported value before calling super.onCreate() because
+        // mFingerprintSupported is used in setupTests() which gets called by super.onCreate().
+        super.onCreate(savedInstanceState);
+
+        mPrepareTestButton.setText(R.string.provisioning_byod_auth_bound_key_set_up);
+        mPrepareTestButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View arg0) {
+                startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
+            }
+        });
+        if (mFingerprintSupported) {
+            requestPermissions(new String[] {Manifest.permission.USE_FINGERPRINT},
+                    FINGERPRINT_PERMISSION_REQUEST_CODE);
+        }
+    }
+
+    private class LockscreenCountDownTester extends CountDownTimer {
+
+        private Toast mToast;
+
+        public LockscreenCountDownTester() {
+            // Wait for AUTHENTICATION_DURATION_SECONDS so the key is evicted before the real test.
+            super(AUTHENTICATION_DURATION_SECONDS * 1000, 1000);
+            mToast = Toast.makeText(AuthenticationBoundKeyTestActivity.this, "", Toast.LENGTH_SHORT);
+        }
+
+        @Override
+        public void onFinish() {
+            mToast.cancel();
+            if (tryEncryptWithLockscreenKey()) {
+                showToast("Test failed. Key accessible without auth.");
+                setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+            } else {
+                // Start the Confirm Credentials screen.
+                Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
+                if (intent != null) {
+                    startActivityForResult(intent, CONFIRM_CREDENTIALS_REQUEST_CODE);
+                } else {
+                    showToast("Test failed. No lockscreen password exists.");
+                    setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                }
+            }
+        }
+
+        @Override
+        public void onTick(long millisUntilFinished) {
+            mToast.setText(String.format("Lockscreen challenge start in %d seconds..",
+                    millisUntilFinished / 1000));
+            mToast.show();
+        }
+    }
+
+
+    @Override
+    protected void setupTests(ArrayTestListAdapter adapter) {
+        mLockScreenBoundKeyTest = new DialogTestListItem(this,
+                R.string.provisioning_byod_lockscreen_bound_key,
+                "BYOD_LockScreenBoundKeyTest") {
+
+            @Override
+            public void performTest(DialogTestListActivity activity) {
+                if (checkPreconditions()) {
+                    createKey(LOCKSCREEN);
+                    new LockscreenCountDownTester().start();
+                }
+            }
+        };
+        adapter.add(mLockScreenBoundKeyTest);
+
+        if (mFingerprintSupported) {
+            mFingerprintBoundKeyTest = new DialogTestListItem(this,
+                    R.string.provisioning_byod_fingerprint_bound_key,
+                    "BYOD_FingerprintBoundKeyTest") {
+
+                @Override
+                public void performTest(DialogTestListActivity activity) {
+                    if (checkPreconditions()) {
+                        createKey(FINGERPRINT);
+                        mFingerprintCipher = initFingerprintEncryptionCipher();
+                        if (tryEncryptWithFingerprintKey(mFingerprintCipher)) {
+                            showToast("Test failed. Key accessible without auth.");
+                            setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                        } else {
+                            new FingerprintAuthDialogFragment().show(getFragmentManager(),
+                                    "fingerprint_dialog");
+                        }
+                    }
+                }
+            };
+            adapter.add(mFingerprintBoundKeyTest);
+        }
+    }
+
+    private boolean checkPreconditions() {
+        if (!mKeyguardManager.isKeyguardSecure()) {
+            showToast("Please set a lockscreen password.");
+            return false;
+        } else if (mFingerprintSupported && !mFingerprintManager.hasEnrolledFingerprints()) {
+            showToast("Please enroll a fingerprint.");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private String getKeyName(int testType) {
+        return testType == LOCKSCREEN ? LOCKSCREEN_KEY_NAME : FINGERPRINT_KEY_NAME;
+    }
+    /**
+     * Creates a symmetric key in the Android Key Store which can only be used after the user has
+     * authenticated with device credentials.
+     */
+    private void createKey(int testType) {
+        try {
+            // Set the alias of the entry in Android KeyStore where the key will appear
+            // and the constrains (purposes) in the constructor of the Builder
+            KeyGenParameterSpec.Builder builder;
+            builder = new KeyGenParameterSpec.Builder(getKeyName(testType),
+                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+                    .setUserAuthenticationRequired(true)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
+            if (testType == LOCKSCREEN) {
+                // Require that the user unlocked the lockscreen in the last 5 seconds
+                builder.setUserAuthenticationValidityDurationSeconds(
+                        AUTHENTICATION_DURATION_SECONDS);
+            }
+            KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                    KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME);
+            keyGenerator.init(builder.build());
+            keyGenerator.generateKey();
+        } catch (NoSuchAlgorithmException | NoSuchProviderException
+                | InvalidAlgorithmParameterException e) {
+            throw new RuntimeException("Failed to create a symmetric key", e);
+        }
+    }
+
+    private SecretKey loadSecretKey(int testType) {
+        try {
+            KeyStore keyStore = KeyStore.getInstance(KEYSTORE_NAME);
+            keyStore.load(null);
+            return (SecretKey) keyStore.getKey(getKeyName(testType), null);
+        } catch (UnrecoverableKeyException  | CertificateException |KeyStoreException | IOException
+                | NoSuchAlgorithmException e) {
+            throw new RuntimeException("Failed to load a symmetric key", e);
+        }
+    }
+
+    private boolean tryEncryptWithLockscreenKey() {
+        try {
+            // Try encrypting something, it will only work if the user authenticated within
+            // the last AUTHENTICATION_DURATION_SECONDS seconds.
+            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+            cipher.init(Cipher.ENCRYPT_MODE, loadSecretKey(LOCKSCREEN));
+            cipher.doFinal(SECRET_BYTE_ARRAY);
+            return true;
+        } catch (UserNotAuthenticatedException e) {
+            // User is not authenticated, let's authenticate with device credentials.
+            return false;
+        } catch (KeyPermanentlyInvalidatedException e) {
+            // This happens if the lock screen has been disabled or reset after the key was
+            // generated.
+            createKey(LOCKSCREEN);
+            showToast("Set up lockscreen after test ran. Retry the test.");
+            return false;
+        } catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException
+                | NoSuchPaddingException | NoSuchAlgorithmException e) {
+            throw new RuntimeException("Encrypt with lockscreen-bound key failed", e);
+        }
+    }
+
+    private Cipher initFingerprintEncryptionCipher() {
+        try {
+            Cipher cipher =  Cipher.getInstance(CIPHER_TRANSFORMATION);
+            cipher.init(Cipher.ENCRYPT_MODE, loadSecretKey(FINGERPRINT));
+            return cipher;
+        } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
+            return null;
+        } catch (KeyPermanentlyInvalidatedException e) {
+            // This happens if the lock screen has been disabled or reset after the key was
+            // generated after the key was generated.
+            createKey(FINGERPRINT);
+            showToast("Set up lockscreen after test ran. Retry the test.");
+            return null;
+        } catch (InvalidKeyException e) {
+            throw new RuntimeException("Init cipher with fingerprint-bound key failed", e);
+        }
+    }
+
+    private boolean tryEncryptWithFingerprintKey(Cipher cipher) {
+
+        try {
+            cipher.doFinal(SECRET_BYTE_ARRAY);
+            return true;
+        } catch (IllegalBlockSizeException e) {
+            // Cannot encrypt, key is unavailable
+            return false;
+        } catch (BadPaddingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected void handleActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+            case CONFIRM_CREDENTIALS_REQUEST_CODE:
+                if (resultCode == RESULT_OK) {
+                    if (tryEncryptWithLockscreenKey()) {
+                        setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_PASSED);
+                    } else {
+                        showToast("Test failed. Key not accessible after auth");
+                        setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                    }
+                } else {
+                    showToast("Lockscreen challenge canceled.");
+                    setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                }
+                break;
+            default:
+                super.handleActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    private void showToast(String message) {
+        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+    }
+
+    public class FingerprintAuthDialogFragment extends DialogFragment {
+
+        private CancellationSignal mCancellationSignal;
+        private FingerprintManagerCallback mFingerprintManagerCallback;
+        private boolean mSelfCancelled;
+
+        class FingerprintManagerCallback extends FingerprintManager.AuthenticationCallback {
+            @Override
+            public void onAuthenticationError(int errMsgId, CharSequence errString) {
+                if (!mSelfCancelled) {
+                    showToast(errString.toString());
+                }
+            }
+
+            @Override
+            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+                showToast(helpString.toString());
+            }
+
+            @Override
+            public void onAuthenticationFailed() {
+                showToast(getString(R.string.sec_fp_auth_failed));
+            }
+
+            @Override
+            public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
+                if (tryEncryptWithFingerprintKey(mFingerprintCipher)) {
+                    showToast("Test passed.");
+                    setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_PASSED);
+                } else {
+                    showToast("Test failed. Key not accessible after auth");
+                    setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                }
+                FingerprintAuthDialogFragment.this.dismiss();
+            }
+        }
+
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            mCancellationSignal.cancel();
+            mSelfCancelled = true;
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            mCancellationSignal = new CancellationSignal();
+            mSelfCancelled = false;
+            mFingerprintManagerCallback = new FingerprintManagerCallback();
+            mFingerprintManager.authenticate(new FingerprintManager.CryptoObject(mFingerprintCipher),
+                    mCancellationSignal, 0, mFingerprintManagerCallback, null);
+            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+            builder.setMessage(R.string.sec_fp_dialog_message);
+            return builder.create();
+        }
+
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index 0200a4f..b129665 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -19,6 +19,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
@@ -59,7 +60,9 @@
     private DialogTestListItem mProfileAccountVisibleTest;
     private DialogTestListItem mDeviceAdminVisibleTest;
     private DialogTestListItem mWorkAppVisibleTest;
-    private DialogTestListItem mCrossProfileIntentFiltersTest;
+    private DialogTestListItem mCrossProfileIntentFiltersTestFromPersonal;
+    private DialogTestListItem mCrossProfileIntentFiltersTestFromWork;
+    private DialogTestListItem mAppLinkingTest;
     private DialogTestListItem mDisableNonMarketTest;
     private DialogTestListItem mEnableNonMarketTest;
     private DialogTestListItem mWorkNotificationBadgedTest;
@@ -78,6 +81,7 @@
     private DialogTestListItem mCrossProfileAudioCaptureSupportTest;
     private TestListItem mKeyguardDisabledFeaturesTest;
     private DialogTestListItem mDisableNfcBeamTest;
+    private TestListItem mAuthenticationBoundKeyTest;
 
     public ByodFlowTestActivity() {
         super(R.layout.provisioning_byod,
@@ -264,20 +268,39 @@
                 R.string.provisioning_byod_print_settings_instruction,
                 new Intent(Settings.ACTION_PRINT_SETTINGS));
 
-        Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+        Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
+        intent.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, false);
         Intent chooser = Intent.createChooser(intent,
                 getResources().getString(R.string.provisioning_cross_profile_chooser));
-        mCrossProfileIntentFiltersTest = new DialogTestListItem(this,
-                R.string.provisioning_byod_cross_profile,
-                "BYOD_CrossProfileIntentFiltersTest",
-                R.string.provisioning_byod_cross_profile_instruction,
+        mCrossProfileIntentFiltersTestFromPersonal = new DialogTestListItem(this,
+                R.string.provisioning_byod_cross_profile_from_personal,
+                "BYOD_CrossProfileIntentFiltersTestFromPersonal",
+                R.string.provisioning_byod_cross_profile_from_personal_instruction,
                 chooser);
 
+        mCrossProfileIntentFiltersTestFromWork = new DialogTestListItem(this,
+                R.string.provisioning_byod_cross_profile_from_work,
+                "BYOD_CrossProfileIntentFiltersTestFromWork",
+                R.string.provisioning_byod_cross_profile_from_work_instruction,
+                new Intent(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG));
+
+        mAppLinkingTest = new DialogTestListItem(this,
+                R.string.provisioning_app_linking,
+                "BYOD_AppLinking",
+                R.string.provisioning_byod_app_linking_instruction,
+                new Intent(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG));
+
         mKeyguardDisabledFeaturesTest = TestListItem.newTest(this,
                 R.string.provisioning_byod_keyguard_disabled_features,
                 KeyguardDisabledFeaturesActivity.class.getName(),
                 new Intent(this, KeyguardDisabledFeaturesActivity.class), null);
 
+        mAuthenticationBoundKeyTest = TestListItem.newTest(this,
+                R.string.provisioning_byod_auth_bound_key,
+                AuthenticationBoundKeyTestActivity.class.getName(),
+                new Intent(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST),
+                null);
+
         // Test for checking if the required intent filters are set during managed provisioning.
         mIntentFiltersTest = new DialogTestListItem(this,
                 R.string.provisioning_byod_cross_profile_intent_filters,
@@ -287,7 +310,7 @@
                 checkIntentFilters();
             }
         };
-        
+
         Intent permissionCheckIntent = new Intent(
                 PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
         mPermissionLockdownTest = new DialogTestListItem(this,
@@ -314,12 +337,15 @@
         adapter.add(mDataUsageSettingsVisibleTest);
         adapter.add(mPrintSettingsVisibleTest);
 
-        adapter.add(mCrossProfileIntentFiltersTest);
+        adapter.add(mCrossProfileIntentFiltersTestFromPersonal);
+        adapter.add(mCrossProfileIntentFiltersTestFromWork);
+        adapter.add(mAppLinkingTest);
         adapter.add(mDisableNonMarketTest);
         adapter.add(mEnableNonMarketTest);
         adapter.add(mIntentFiltersTest);
         adapter.add(mPermissionLockdownTest);
         adapter.add(mKeyguardDisabledFeaturesTest);
+        adapter.add(mAuthenticationBoundKeyTest);
 
         if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
             // Capture image intent can be resolved in primary profile, so test.
@@ -495,7 +521,8 @@
             ByodHelperActivity.class.getName(),
             WorkNotificationTestActivity.class.getName(),
             WorkStatusTestActivity.class.getName(),
-            PermissionLockdownTestActivity.ACTIVITY_ALIAS
+            PermissionLockdownTestActivity.ACTIVITY_ALIAS,
+            AuthenticationBoundKeyTestActivity.class.getName()
         };
         for (String component : components) {
             getPackageManager().setComponentEnabledSetting(new ComponentName(this, component),
@@ -503,4 +530,5 @@
                     PackageManager.DONT_KILL_APP);
         }
     }
+
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 3d7d42d..9ea5061 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -27,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.UserManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.support.v4.content.FileProvider;
@@ -84,6 +85,18 @@
     public static final String ACTION_CHECK_INTENT_FILTERS =
             "com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS";
 
+    // Primary -> managed intent: will send a cross profile intent and check if the user sees an
+    // intent picker dialog and can open the apps.
+    public static final String ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG =
+            "com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG";
+
+    // Primary -> managed intent: will send an app link intent and check if the user sees a
+    // dialog and can open the apps. This test is extremely similar to
+    // ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG, but the intent used is a web intent, and there is
+    // some behavior which is specific to web intents.
+    public static final String ACTION_TEST_APP_LINKING_DIALOG =
+            "com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG";
+
     public static final int RESULT_FAILED = RESULT_FIRST_USER;
 
     private static final int REQUEST_INSTALL_PACKAGE = 1;
@@ -211,6 +224,16 @@
             startActivity(testNfcBeamIntent);
             finish();
             return;
+        } else if (action.equals(ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG)) {
+            sendIntentInsideChooser(new Intent(
+                    CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL));
+        } else if (action.equals(ACTION_TEST_APP_LINKING_DIALOG)) {
+            mDevicePolicyManager.addUserRestriction(
+                    DeviceAdminTestReceiver.getReceiverComponentName(),
+                    UserManager.ALLOW_PARENT_PROFILE_APP_LINKING);
+            Intent toSend = new Intent(Intent.ACTION_VIEW);
+            toSend.setData(Uri.parse("http://com.android.cts.verifier"));
+            sendIntentInsideChooser(toSend);
         }
         // This activity has no UI and is only used to respond to CtsVerifier in the primary side.
         finish();
@@ -346,6 +369,13 @@
                 DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
     }
 
+    private void sendIntentInsideChooser(Intent toSend) {
+        toSend.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, true);
+        Intent chooser = Intent.createChooser(toSend,
+                getResources().getString(R.string.provisioning_cross_profile_chooser));
+        startActivity(chooser);
+    }
+
     @Override
     public void onDialogClose() {
         finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
index b3f126b..15f5bc8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
@@ -31,10 +31,14 @@
 import android.widget.ImageView;
 import android.widget.Toast;
 import android.widget.VideoView;
-
+import android.view.Display;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.content.ContentResolver;
 import com.android.cts.verifier.R;
 
 import java.io.IOException;
+import java.io.InputStream;
 
 /**
  * This dialog shows/plays an image, video or audio uri.
@@ -46,6 +50,7 @@
     private static final String KEY_IMAGE_URI = "image";
     private static final String KEY_AUDIO_URI = "audio";
 
+    private Bitmap scaled = null;
     /**
      * Get a dialogFragment showing an image.
      */
@@ -79,6 +84,16 @@
         return dialog;
     }
 
+    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
+        // Raw height and width of image
+        final int height = options.outHeight;
+        final int width = options.outWidth;
+        if(reqWidth <= 0 || reqHeight <= 0) {
+           return 1;
+        }
+        return Math.max(height/reqHeight, width/reqWidth) + 1;
+    }
+
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         final Dialog dialog = new Dialog(getActivity());
@@ -114,11 +129,36 @@
         } else if (arguments.containsKey(KEY_IMAGE_URI)) {
             // Show image UI.
             dialog.setTitle(getString(R.string.provisioning_byod_verify_image_title));
-
-            Uri uri = (Uri) getArguments().getParcelable(KEY_IMAGE_URI);
+            Uri uri = (Uri)getArguments().getParcelable(KEY_IMAGE_URI);
             ImageView imageView = (ImageView) dialog.findViewById(R.id.imageView);
             imageView.setVisibility(View.VISIBLE);
-            imageView.setImageURI(uri);
+
+            try{
+                InputStream input = getActivity().getContentResolver().openInputStream(uri);
+                BitmapFactory.Options options = new BitmapFactory.Options();
+                options.inJustDecodeBounds = true;
+                BitmapFactory.decodeStream(input, null, options);
+                //scale the picture
+                Display display = getActivity().getWindowManager().getDefaultDisplay();
+                Point size = new Point();
+                display.getSize(size);
+                int reqWidth = size.x;
+                int reqHeight = size.y;
+                options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+
+                options.inJustDecodeBounds = false;
+                input.close();
+                input = getActivity().getContentResolver().openInputStream(uri);
+                scaled = BitmapFactory.decodeStream(input, null, options);
+                input.close();
+                imageView.setImageBitmap(scaled);
+            }catch(IOException e){
+                Log.e(TAG, "Cannot get image.", e);
+                Toast.makeText(getActivity(),R.string.provisioning_byod_capture_image_error,
+                        Toast.LENGTH_SHORT).show();
+                getActivity().finish();
+            }
+
         } else if (arguments.containsKey(KEY_AUDIO_URI)) {
             // Show audio playback UI.
             dialog.setTitle(getString(R.string.provisioning_byod_verify_audio_title));
@@ -161,6 +201,13 @@
         ((DialogCallback) getActivity()).onDialogClose();
     }
 
+    @Override
+    public void onDestroyView() {
+        if(scaled!=null){
+            scaled.recycle();
+        }
+        super.onDestroyView();
+    }
     public interface DialogCallback {
         public abstract void onDialogClose();
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
index 6c38e12..3f316f21 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
@@ -35,7 +35,12 @@
  */
 public class CrossProfileTestActivity extends Activity {
     // Intent for app in both profiles
-    public static final String ACTION_CROSS_PROFILE = "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE";
+    public static final String ACTION_CROSS_PROFILE_TO_PERSONAL =
+            "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL";
+    public static final String ACTION_CROSS_PROFILE_TO_WORK =
+            "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK";
+    public static final String EXTRA_STARTED_FROM_WORK
+            = "com.android.cts.verifier.managedprovisioning.STARTED_FROM_WORK";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -45,9 +50,15 @@
 
         // Check if we are running in the work or personal side, by testing if currently we are the
         // profile owner or not.
-        textView.setText(isProfileOwner() ? R.string.provisioning_byod_cross_profile_app_work
-                : R.string.provisioning_byod_cross_profile_app_personal);
-
+        boolean inWorkProfile = isProfileOwner();
+        boolean startedFromWork = getIntent().getBooleanExtra(EXTRA_STARTED_FROM_WORK, false);
+        if (inWorkProfile && !startedFromWork) {
+            textView.setText(R.string.provisioning_byod_cross_profile_app_work);
+        } else if (!inWorkProfile && startedFromWork) {
+            textView.setText(R.string.provisioning_byod_cross_profile_app_personal);
+        } else { // started from the same side we're currently running in
+            textView.setText(R.string.provisioning_byod_cross_profile_app_ctsverifier);
+        }
         findViewById(R.id.button_finish).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 008091b..ed6b5eb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -64,7 +64,9 @@
             filter.addAction(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES);
             filter.addAction(ByodHelperActivity.ACTION_LOCKNOW);
             filter.addAction(ByodHelperActivity.ACTION_TEST_NFC_BEAM);
-            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+            filter.addAction(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG);
+            filter.addAction(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG);
+            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN);
             filter.addAction(WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION);
@@ -72,12 +74,14 @@
             filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_ICON);
             filter.addAction(
                     PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
+            filter.addAction(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST);
             dpm.addCrossProfileIntentFilter(getWho(context), filter,
                     DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
 
             // Work -> primary direction
             filter = new IntentFilter();
             filter.addAction(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
+            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL);
             dpm.addCrossProfileIntentFilter(getWho(context), filter,
                     DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
index 7dc99c0..eef6299 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -30,6 +30,7 @@
 import android.net.Uri;
 import android.nfc.cardemulation.CardEmulation;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.UserHandle;
 import android.provider.AlarmClock;
 import android.provider.CalendarContract.Events;
@@ -39,6 +40,7 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -51,132 +53,83 @@
     private static final String TAG = "IntentFiltersTestHelper";
 
     // These are the intents which can be forwarded to the managed profile.
-    private static final Intent[] forwardedIntentsFromPrimary = new Intent[] {
-        new Intent(Intent.ACTION_SEND).setType("*/*"),
-        new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*")
-    };
+    private static final ArrayList<Intent> forwardedIntentsFromPrimary =
+            new ArrayList<>(Arrays.asList(
+                new Intent(Intent.ACTION_SEND).setType("*/*"),
+                new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*")
+            ));
 
     // These are the intents which can be forwarded to the primary profile.
-    private static final Intent[] forwardedIntentsFromManaged = new Intent[] {
-        new Intent(AlarmClock.ACTION_SET_ALARM),
-        new Intent(AlarmClock.ACTION_SET_TIMER),
-        new Intent(AlarmClock.ACTION_SHOW_ALARMS),
-        new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
-        new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
-        new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA),
-        new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA),
-        new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE),
-        new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
-        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")),
-        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")),
-        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")),
-        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("sms:07700900100?body=Hello%20world")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("mms:07700900100?body=Hello%20world")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
-        new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS),
-        new Intent(Settings.ACTION_APN_SETTINGS),
-        new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS),
-        new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
-        new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS),
-        new Intent(Settings.ACTION_DATE_SETTINGS),
-        new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
-        new Intent(Settings.ACTION_DISPLAY_SETTINGS),
-        new Intent(Settings.ACTION_DREAM_SETTINGS),
-        new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
-        new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS),
-        new Intent(Settings.ACTION_LOCALE_SETTINGS),
-        new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS),
-        new Intent(Settings.ACTION_NFC_SETTINGS),
-        new Intent(Settings.ACTION_NFCSHARING_SETTINGS),
-        new Intent(Settings.ACTION_PRIVACY_SETTINGS),
-        new Intent(Settings.ACTION_SETTINGS),
-        new Intent(Settings.ACTION_SOUND_SETTINGS),
-        new Intent(Settings.ACTION_WIRELESS_SETTINGS),
-        new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
-        new Intent("android.net.vpn.SETTINGS"),
-        new Intent(CardEmulation.ACTION_CHANGE_DEFAULT),
-        new Intent("android.settings.ACCOUNT_SYNC_SETTINGS"),
-        new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
-        new Intent(Settings.ACTION_HOME_SETTINGS),
-        new Intent("android.settings.LICENSE"),
-        new Intent("android.settings.NOTIFICATION_SETTINGS"),
-        new Intent(Settings.ACTION_SHOW_REGULATORY_INFO),
-        new Intent("android.settings.USER_SETTINGS"),
-        new Intent("android.settings.ZEN_MODE_SETTINGS"),
-        new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"),
-        new Intent("com.android.settings.STORAGE_USB_SETTINGS"),
-        new Intent("com.android.settings.TTS_SETTINGS"),
-        new Intent("com.android.settings.USER_DICTIONARY_EDIT"),
-        new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")),
-        new Intent("android.intent.action.CALL_EMERGENCY").setData(Uri.parse("tel:123")),
-        new Intent("android.intent.action.CALL_PRIVILEGED").setData(Uri.parse("tel:123")),
-        new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
-        new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS),
-        new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS),
-        new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS),
-        new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
-        new Intent(Settings.ACTION_SYNC_SETTINGS),
-        new Intent(Settings.ACTION_ADD_ACCOUNT),
-        new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory(
-                Intent.CATEGORY_OPENABLE),
-        new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory(
-                Intent.CATEGORY_OPENABLE),
-        new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS),
-        new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS),
-        new Intent(Settings.ACTION_APPLICATION_SETTINGS),
-        new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS"),
-        new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION),
-        new Intent(Settings.ACTION_WIFI_IP_SETTINGS),
-        new Intent(Settings.ACTION_WIFI_SETTINGS),
-        new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
-    };
+    private static final ArrayList<Intent> forwardedIntentsFromManaged =
+            new ArrayList<>(Arrays.asList(
+                new Intent(AlarmClock.ACTION_SET_ALARM),
+                new Intent(AlarmClock.ACTION_SET_TIMER),
+                new Intent(AlarmClock.ACTION_SHOW_ALARMS),
+                new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
+                new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS),
+                new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
+                new Intent(Settings.ACTION_DATE_SETTINGS),
+                new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
+                new Intent(Settings.ACTION_DISPLAY_SETTINGS),
+                new Intent(Settings.ACTION_LOCALE_SETTINGS),
+                new Intent(Settings.ACTION_PRIVACY_SETTINGS),
+                new Intent(Settings.ACTION_SETTINGS),
+                new Intent(Settings.ACTION_WIRELESS_SETTINGS),
+                new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
+                new Intent("android.net.vpn.SETTINGS"),
+                new Intent("android.settings.ACCOUNT_SYNC_SETTINGS"),
+                new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
+                new Intent("android.settings.LICENSE"),
+                new Intent("android.settings.NOTIFICATION_SETTINGS"),
+                new Intent("android.settings.USER_SETTINGS"),
+                new Intent("android.settings.ZEN_MODE_SETTINGS"),
+                new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"),
+                new Intent("com.android.settings.STORAGE_USB_SETTINGS"),
+                new Intent("com.android.settings.TTS_SETTINGS"),
+                new Intent("com.android.settings.USER_DICTIONARY_EDIT"),
+                new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
+                new Intent(Settings.ACTION_SYNC_SETTINGS),
+                new Intent(Settings.ACTION_ADD_ACCOUNT),
+                new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory(
+                        Intent.CATEGORY_OPENABLE),
+                new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory(
+                        Intent.CATEGORY_OPENABLE),
+                new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS),
+                new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS),
+                new Intent(Settings.ACTION_APPLICATION_SETTINGS)
+            ));
 
     // These are the intents which cannot be forwarded to the primary profile.
-    private static final Intent[] notForwardedIntentsFromManaged = new Intent[] {
-        new Intent(Intent.ACTION_INSERT).setData(
-                Uri.parse("content://browser/bookmarks")),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("http://www.example.com")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Intent.ACTION_SENDTO).setData(
-                Uri.parse("mailto:user@example.com")),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("mailto:user@example.com")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("geo:0,0?q=BuckinghamPalace")),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("http://example.com/oceans.mp4")).setType("video/mp4"),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("http://www.example.com/horse.mp3")).setType("audio/*"),
-        new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH),
-        new Intent(Intent.ACTION_VIEW).setData(
-                Uri.parse("market://details?id=com.android.chrome")).addCategory(
-                Intent.CATEGORY_BROWSABLE),
-        new Intent(Intent.ACTION_WEB_SEARCH),
-        new Intent(Settings.ACTION_SEARCH_SETTINGS),
-        new Intent(Settings.ACTION_PRINT_SETTINGS),
-        new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE),
-        new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
-                Uri.parse("package:com.android.chrome")),
-        new Intent("android.settings.SHOW_INPUT_METHOD_PICKER"),
-        new Intent(Intent.ACTION_INSERT).setData(Events.CONTENT_URI),
-        new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL),
-        new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
-    };
+    private static final ArrayList<Intent> notForwardedIntentsFromManaged =
+            new ArrayList<>(Arrays.asList(
+                new Intent(Intent.ACTION_INSERT).setData(
+                        Uri.parse("content://browser/bookmarks")),
+                new Intent(Intent.ACTION_VIEW).setData(
+                        Uri.parse("http://www.example.com")).addCategory(
+                        Intent.CATEGORY_BROWSABLE),
+                new Intent(Intent.ACTION_SENDTO).setData(
+                        Uri.parse("mailto:user@example.com")),
+                new Intent(Intent.ACTION_VIEW).setData(
+                        Uri.parse("mailto:user@example.com")).addCategory(
+                        Intent.CATEGORY_BROWSABLE),
+                new Intent(Intent.ACTION_VIEW).setData(
+                        Uri.parse("geo:0,0?q=BuckinghamPalace")),
+                new Intent(Intent.ACTION_VIEW).setData(
+                        Uri.parse("http://example.com/oceans.mp4")).setType("video/mp4"),
+                new Intent(Intent.ACTION_VIEW).setData(
+                        Uri.parse("http://www.example.com/horse.mp3")).setType("audio/*"),
+                new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH),
+                new Intent(Intent.ACTION_VIEW).setData(
+                        Uri.parse("market://details?id=com.android.chrome")).addCategory(
+                        Intent.CATEGORY_BROWSABLE),
+                new Intent(Intent.ACTION_WEB_SEARCH),
+                new Intent(Settings.ACTION_SEARCH_SETTINGS),
+                new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE),
+                new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
+                        Uri.parse("package:com.android.chrome")),
+                new Intent(Intent.ACTION_INSERT).setData(Events.CONTENT_URI),
+                new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
+            ));
 
     // This flag specifies we are dealing with intents fired from the primary profile.
     public static final int FLAG_INTENTS_FROM_PRIMARY = 1;
@@ -187,6 +140,124 @@
 
     IntentFiltersTestHelper(Context context) {
         mContext = context;
+
+        addIntentsThatDependOnDeviceFeatures();
+    }
+
+    private void addIntentsThatDependOnDeviceFeatures() {
+        PackageManager pm = mContext.getPackageManager();
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            forwardedIntentsFromManaged.addAll(Arrays.asList(
+                    new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
+                    new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")),
+                    new Intent("android.intent.action.CALL_EMERGENCY").setData(
+                            Uri.parse("tel:123")),
+                    new Intent("android.intent.action.CALL_PRIVILEGED").setData(
+                            Uri.parse("tel:123")),
+                    new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory(
+                            Intent.CATEGORY_BROWSABLE),
+                    new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS),
+                    new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS),
+                    new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")),
+                    new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")),
+                    new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")),
+                    new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")),
+                    new Intent(Intent.ACTION_VIEW).setData(
+                            Uri.parse("sms:07700900100?body=Hello%20world")).addCategory(
+                            Intent.CATEGORY_BROWSABLE),
+                    new Intent(Intent.ACTION_VIEW).setData(
+                            Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory(
+                            Intent.CATEGORY_BROWSABLE),
+                    new Intent(Intent.ACTION_VIEW).setData(
+                            Uri.parse("mms:07700900100?body=Hello%20world")).addCategory(
+                            Intent.CATEGORY_BROWSABLE),
+                    new Intent(Intent.ACTION_VIEW).setData(
+                            Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
+                            Intent.CATEGORY_BROWSABLE),
+                    new Intent(Settings.ACTION_APN_SETTINGS)));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+            forwardedIntentsFromManaged.addAll(Arrays.asList(
+                    new Intent(Settings.ACTION_NFC_SETTINGS),
+                    new Intent(Settings.ACTION_NFCSHARING_SETTINGS),
+                    new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS)));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
+            forwardedIntentsFromManaged.add(
+                    new Intent(CardEmulation.ACTION_CHANGE_DEFAULT));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
+            forwardedIntentsFromManaged.addAll(Arrays.asList(
+                    new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
+                    new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
+                    new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA),
+                    new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA),
+                    new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE),
+                    new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)));
+        }
+
+        final String state = Environment.getExternalStorageState();
+        if (Environment.MEDIA_MOUNTED.equals(state)) {
+            forwardedIntentsFromManaged.add(
+                    new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+            forwardedIntentsFromManaged.addAll(Arrays.asList(
+                    new Intent(Settings.ACTION_WIFI_IP_SETTINGS),
+                    new Intent(Settings.ACTION_WIFI_SETTINGS)));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+            forwardedIntentsFromManaged.addAll(Arrays.asList(
+                    new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION),
+                    new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_LOCATION)) {
+            forwardedIntentsFromManaged.add(
+                    new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
+            forwardedIntentsFromManaged.addAll(Arrays.asList(
+                    new Intent(Settings.ACTION_SOUND_SETTINGS),
+                    new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS")));
+            notForwardedIntentsFromManaged.add(
+                    new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_HOME_SCREEN)) {
+            forwardedIntentsFromManaged.add(
+                    new Intent(Settings.ACTION_HOME_SETTINGS));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) {
+            forwardedIntentsFromManaged.addAll(Arrays.asList(
+                    new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
+                    new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS)));
+            notForwardedIntentsFromManaged.add(
+                    new Intent("android.settings.SHOW_INPUT_METHOD_PICKER"));
+        }
+
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            forwardedIntentsFromManaged.add(
+                    new Intent(Settings.ACTION_DREAM_SETTINGS));
+        }
+
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            forwardedIntentsFromManaged.add(
+                    new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS));
+        }
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
+            notForwardedIntentsFromManaged.add(
+                    new Intent(Settings.ACTION_PRINT_SETTINGS));
+        }
     }
 
     public boolean checkCrossProfileIntentFilters(int flag) {
@@ -298,7 +369,7 @@
      * @return {@code null} if all the intents are correctly handled
      *         otherwise, the first intent in the list which is not handled correctly.
      */
-    private Intent checkForIntentsNotHandled(Intent[] intentList,
+    private Intent checkForIntentsNotHandled(ArrayList<Intent> intentList,
             ActivityInfo expectedForwarderActivityInfo, boolean canResolve) {
         for (Intent intent : intentList) {
             if (canForwarderActivityHandleIntent(intent,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java
index 8e72ebb..0728fb5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java
@@ -31,6 +31,8 @@
 
     private static final String TAG = "ScreenPinningTestActivity";
     private static final String KEY_CURRENT_TEST = "keyCurrentTest";
+    private static final long TASK_MODE_CHECK_DELAY = 200;
+    private static final int MAX_TASK_MODE_CHECK_COUNT = 5;
 
     private Test[] mTests;
     private int mTestIndex;
@@ -203,10 +205,18 @@
                 return;
             }
             stopLockTask();
-            if (!mActivityManager.isInLockTaskMode()) {
-                succeed();
-            } else {
-                error(R.string.error_screen_pinning_couldnt_exit);
+            for (int retry = MAX_TASK_MODE_CHECK_COUNT; retry > 0; retry--) {
+                try {
+                    Thread.sleep(TASK_MODE_CHECK_DELAY);
+                } catch (InterruptedException e) {
+                }
+                Log.d(TAG, "Check unpin ... " + retry);
+                if (!mActivityManager.isInLockTaskMode()) {
+                    succeed();
+                    break;
+                } else if (retry == 1) {
+                    error(R.string.error_screen_pinning_couldnt_exit);
+                }
             }
         };
     };
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
index 70899c6..bca7a66 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
@@ -89,6 +89,22 @@
         if (requestCode == FINGERPRINT_PERMISSION_REQUEST_CODE && state[0] == PackageManager.PERMISSION_GRANTED) {
             mFingerprintManager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
             mKeyguardManager = (KeyguardManager) getSystemService(KeyguardManager.class);
+            Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
+
+            if (!mKeyguardManager.isKeyguardSecure()) {
+                // Show a message that the user hasn't set up a lock screen.
+                showToast( "Secure lock screen hasn't been set up.\n"
+                                + "Go to 'Settings -> Security -> Screen lock' to set up a lock screen");
+                startTestButton.setEnabled(false);
+                return;
+            } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
+                showToast("No fingerprints enrolled.\n"
+                                + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint");
+                startTestButton.setEnabled(false);
+                return;
+            }
+
+            createKey();
 
             try {
                 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
@@ -107,7 +123,6 @@
                 throw new RuntimeException("Failed to init Cipher", e);
             }
 
-            Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
             startTestButton.setOnClickListener(new OnClickListener() {
                 @Override
                 public void onClick(View v) {
@@ -117,21 +132,7 @@
                         showAuthenticationScreen();
                     }
                 }
-
             });
-
-            if (!mKeyguardManager.isKeyguardSecure()) {
-                // Show a message that the user hasn't set up a lock screen.
-                showToast( "Secure lock screen hasn't been set up.\n"
-                                + "Go to 'Settings -> Security -> Screen lock' to set up a lock screen");
-                startTestButton.setEnabled(false);
-            } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
-                showToast("No fingerprints enrolled.\n"
-                                + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint");
-                startTestButton.setEnabled(false);
-            } else {
-                createKey();
-            }
         }
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
index a5b58f6..fa89b71 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
@@ -23,9 +23,9 @@
 import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.ViewGroup;
 
 import java.io.IOException;
-import java.util.List;
 
 /** Camera preview class */
 public class RVCVCameraPreview extends SurfaceView implements SurfaceHolder.Callback {
@@ -34,15 +34,16 @@
 
     private SurfaceHolder mHolder;
     private Camera mCamera;
+    private float mAspect;
+    private int mRotation;
 
     /**
      * Constructor
      * @param context Activity context
-     * @param camera Camera object to be previewed
      */
-    public RVCVCameraPreview(Context context, Camera camera) {
+    public RVCVCameraPreview(Context context) {
         super(context);
-        mCamera = camera;
+        mCamera = null;
         initSurface();
     }
 
@@ -55,8 +56,10 @@
         super(context, attrs);
     }
 
-    public void init(Camera camera) {
+    public void init(Camera camera, float aspectRatio, int rotation)  {
         this.mCamera = camera;
+        mAspect = aspectRatio;
+        mRotation = rotation;
         initSurface();
     }
 
@@ -86,6 +89,20 @@
         try {
             mCamera.setPreviewDisplay(holder);
             mCamera.startPreview();
+            int v_height = getHeight();
+            int v_width = getWidth();
+            ViewGroup.LayoutParams layout = getLayoutParams();
+            if ( (float)v_height/v_width  >
+                    mAspect) {
+                layout.height = (int)(v_width * mAspect);
+                layout.width = v_width;
+            }else {
+                layout.width = (int)(v_height / mAspect);
+                layout.height = v_height;
+            }
+            Log.d(TAG, String.format("Layout (%d, %d) -> (%d, %d)", v_width, v_height,
+                    layout.width, layout.height));
+            setLayoutParams(layout);
         } catch (IOException e) {
             if (LOCAL_LOGD) Log.d(TAG, "Error when starting camera preview: " + e.getMessage());
         }
@@ -111,8 +128,7 @@
         // stop preview before making changes
         mCamera.stopPreview();
 
-        // the activity using this view is locked to this orientation, so hard code is fine
-        mCamera.setDisplayOrientation(90);
+        mCamera.setDisplayOrientation(mRotation);
 
         //do the same as if it is created again
         surfaceCreated(holder);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
index f90b27c..be5ec52 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
@@ -46,6 +46,7 @@
 import java.io.OutputStreamWriter;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.List;
 
 
 // ----------------------------------------------------------------------
@@ -67,7 +68,7 @@
     private VideoRecorder           mVideoRecorder;
     private RVSensorLogger          mRVSensorLogger;
     private CoverageManager         mCoverManager;
-    private CameraPreviewer         mPreviewer;
+    private CameraContext mCameraContext;
 
     public static final int AXIS_NONE = 0;
     public static final int AXIS_ALL = SensorManager.AXIS_X +
@@ -99,7 +100,7 @@
         super.onPause();
         mController.quit();
 
-        mPreviewer.end();
+        mCameraContext.end();
         endSoundPool();
     }
 
@@ -128,8 +129,8 @@
      *
      */
     private void init() {
-        mPreviewer = new CameraPreviewer();
-        mPreviewer.init();
+        mCameraContext = new CameraContext();
+        mCameraContext.init();
 
         mCoverManager = new CoverageManager();
         mIndicatorView.setDataProvider(
@@ -140,7 +141,7 @@
         initSoundPool();
         mRVSensorLogger = new RVSensorLogger(this);
 
-        mVideoRecorder = new VideoRecorder(mPreviewer.getCamera());
+        mVideoRecorder = new VideoRecorder(mCameraContext.getCamera(), mCameraContext.getProfile());
 
         if (LOG_RAW_SENSORS) {
             mRawSensorLogger = new RawSensorLogger(mRecordDir);
@@ -173,7 +174,8 @@
         // X and Y
         final String axisName = "YXZ";
 
-        message("Manipulate the device in " + axisName.charAt(axis-1) + " axis (as illustrated) about the pattern.");
+        message("Manipulate the device in " + axisName.charAt(axis - 1) +
+                " axis (as illustrated) about the pattern.");
     }
 
     /**
@@ -250,20 +252,28 @@
      * Start the sensor recording
      */
     public void startRecordSensor() {
-        mRVSensorLogger.init();
-        if (LOG_RAW_SENSORS) {
-            mRawSensorLogger.init();
-        }
+        runOnUiThread(new Runnable() {
+            public void run() {
+                mRVSensorLogger.init();
+                if (LOG_RAW_SENSORS) {
+                    mRawSensorLogger.init();
+                }
+            }
+        });
     }
 
     /**
      * Stop the sensor recording
      */
     public void stopRecordSensor() {
-        mRVSensorLogger.end();
-        if (LOG_RAW_SENSORS) {
-            mRawSensorLogger.end();
-        }
+        runOnUiThread(new Runnable() {
+            public void run() {
+                mRVSensorLogger.end();
+                if (LOG_RAW_SENSORS) {
+                    mRawSensorLogger.end();
+                }
+            }
+        });
     }
 
     /**
@@ -365,20 +375,93 @@
     /**
      * Camera preview control class
      */
-    class CameraPreviewer {
+    class CameraContext {
         private Camera mCamera;
+        private CamcorderProfile mProfile;
+        private Camera.CameraInfo mCameraInfo;
 
-        CameraPreviewer() {
+        private int [] mPreferredProfiles = {
+                CamcorderProfile.QUALITY_480P,  // smaller -> faster
+                CamcorderProfile.QUALITY_720P,
+                CamcorderProfile.QUALITY_1080P,
+                CamcorderProfile.QUALITY_HIGH // existence guaranteed
+        };
+
+        CameraContext() {
             try {
-                mCamera = Camera.open(); // attempt to get a default Camera instance
+                mCamera = Camera.open(); // attempt to get a default Camera instance (0)
+                mProfile = null;
+                if (mCamera != null) {
+                    mCameraInfo = new Camera.CameraInfo();
+                    Camera.getCameraInfo(0, mCameraInfo);
+                    setupCamera();
+                }
             }
-            catch (Exception e) {
+            catch (Exception e){
                 // Camera is not available (in use or does not exist)
                 Log.e(TAG, "Cannot obtain Camera!");
             }
         }
 
         /**
+         * Find a preferred camera profile and set preview and picture size property accordingly.
+         */
+        void setupCamera() {
+            CamcorderProfile profile = null;
+            Camera.Parameters param = mCamera.getParameters();
+            List<Camera.Size> pre_sz = param.getSupportedPreviewSizes();
+            List<Camera.Size> pic_sz = param.getSupportedPictureSizes();
+
+            for (int i : mPreferredProfiles) {
+                if (CamcorderProfile.hasProfile(i)) {
+                    profile = CamcorderProfile.get(i);
+
+                    int valid = 0;
+                    for (Camera.Size j : pre_sz) {
+                        if (j.width == profile.videoFrameWidth &&
+                                j.height == profile.videoFrameHeight) {
+                            ++valid;
+                            break;
+                        }
+                    }
+                    for (Camera.Size j : pic_sz) {
+                        if (j.width == profile.videoFrameWidth &&
+                                j.height == profile.videoFrameHeight) {
+                            ++valid;
+                            break;
+                        }
+                    }
+                    if (valid == 2) {
+                        param.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
+                        param.setPictureSize(profile.videoFrameWidth, profile.videoFrameHeight);
+                        mCamera.setParameters(param);
+                        break;
+                    } else {
+                        profile = null;
+                    }
+                }
+            }
+            if (profile != null) {
+                float fovW = param.getHorizontalViewAngle();
+                float fovH = param.getVerticalViewAngle();
+                writeVideoMetaInfo(profile.videoFrameWidth, profile.videoFrameHeight,
+                        profile.videoFrameRate, fovW, fovH);
+            } else {
+                Log.e(TAG, "Cannot find a proper video profile");
+            }
+            mProfile = profile;
+
+        }
+
+
+        /**
+         * Get sensor information of the camera being used
+         */
+        public Camera.CameraInfo getCameraInfo() {
+            return mCameraInfo;
+        }
+
+        /**
          * Get the camera to be previewed
          * @return Reference to Camera used
          */
@@ -387,12 +470,20 @@
         }
 
         /**
+         * Get the camera profile to be used
+         * @return Reference to Camera profile
+         */
+        public CamcorderProfile getProfile() {
+            return mProfile;
+        }
+
+        /**
          * Setup the camera
          */
         public void init() {
             if (mCamera != null) {
                 double alpha = mCamera.getParameters().getHorizontalViewAngle()*Math.PI/180.0;
-                int width = 1920;
+                int width = mProfile.videoFrameWidth;
                 double fx = width/2/Math.tan(alpha/2.0);
 
                 if (LOCAL_LOGV) Log.v(TAG, "View angle="
@@ -400,7 +491,9 @@
 
                 RVCVCameraPreview cameraPreview =
                         (RVCVCameraPreview) findViewById(R.id.cam_preview);
-                cameraPreview.init(mCamera);
+                cameraPreview.init(mCamera,
+                        (float)mProfile.videoFrameWidth/mProfile.videoFrameHeight,
+                        mCameraInfo.orientation);
             } else {
                 message("Cannot open camera!");
                 finish();
@@ -466,26 +559,22 @@
     class VideoRecorder
     {
         private MediaRecorder mRecorder;
+        private CamcorderProfile mProfile;
         private Camera mCamera;
         private boolean mRunning = false;
 
-        private int [] mPreferredProfiles = {   CamcorderProfile.QUALITY_480P,  // smaller -> faster
-                                        CamcorderProfile.QUALITY_720P,
-                                        CamcorderProfile.QUALITY_1080P,
-                                        CamcorderProfile.QUALITY_HIGH // existence guaranteed
-                                    };
-
-
-        VideoRecorder(Camera camera) {
+        VideoRecorder(Camera camera, CamcorderProfile profile){
             mCamera = camera;
+            mProfile = profile;
         }
 
         /**
          * Initialize and start recording
          */
         public void init() {
-            float fovW =  mCamera.getParameters().getHorizontalViewAngle();
-            float fovH =  mCamera.getParameters().getVerticalViewAngle();
+            if (mCamera == null  || mProfile ==null){
+                return;
+            }
 
             mRecorder = new MediaRecorder();
             mCamera.unlock();
@@ -494,17 +583,7 @@
             mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
             mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
 
-            CamcorderProfile profile = null;
-            for (int i: mPreferredProfiles) {
-                if (CamcorderProfile.hasProfile(i)) {
-                    profile = CamcorderProfile.get(i);
-                    mRecorder.setProfile(profile);
-                    break;
-                }
-            }
-
-            writeVideoMetaInfo(profile.videoFrameWidth, profile.videoFrameHeight,
-                    profile.videoFrameRate, fovW, fovH);
+            mRecorder.setProfile(mProfile);
 
             try {
                 mRecorder.setOutputFile(getVideoRecFilePath());
@@ -689,8 +768,20 @@
          */
         public void init() {
             mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
+            if (mSensorManager == null) {
+                Log.e(TAG,"SensorManager is null!");
+            }
             mRVSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
-            mSensorManager.registerListener(this, mRVSensor, SENSOR_RATE);
+            if (mRVSensor != null) {
+                if (LOCAL_LOGV) Log.v(TAG, "Got RV Sensor");
+            }else {
+                Log.e(TAG, "Did not get RV sensor");
+            }
+            if(mSensorManager.registerListener(this, mRVSensor, SENSOR_RATE)) {
+                if (LOCAL_LOGV) Log.v(TAG,"Register listener successfull");
+            } else {
+                Log.e(TAG,"Register listener failed");
+            }
 
             try {
                 mLogWriter= new OutputStreamWriter(
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
index 9afd1a9..3dc7270 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
@@ -15,12 +15,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 import android.media.MediaCodec;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.os.Debug;
 import android.os.Environment;
+import android.os.PowerManager;
 import android.util.JsonWriter;
 import android.util.Log;
 
@@ -777,14 +777,16 @@
         VideoMetaInfo meta = new VideoMetaInfo(new File(mPath, "videometa.json"));
 
         int decimation = 1;
+        boolean use_timestamp = true;
 
+        // roughly determine if decimation is necessary
         if (meta.fps > DECIMATION_FPS_TARGET) {
             decimation = (int)(meta.fps / DECIMATION_FPS_TARGET);
             meta.fps /=decimation;
         }
 
         VideoDecoderForOpenCV videoDecoder = new VideoDecoderForOpenCV(
-                new File(mPath, "video.mp4"), decimation); // every 3 frame process 1 frame
+                new File(mPath, "video.mp4"), decimation);
 
 
         Mat frame;
@@ -820,12 +822,17 @@
         }
 
         long startTime = System.nanoTime();
+        long [] ts = new long[1];
 
-        while ((frame = videoDecoder.getFrame()) !=null) {
+        while ((frame = videoDecoder.getFrame(ts)) !=null) {
             if (LOCAL_LOGV) {
                 Log.v(TAG, "got a frame " + i);
             }
 
+            if (use_timestamp && ts[0] == -1) {
+                use_timestamp = false;
+            }
+
             // has to be in front, as there are cases where execution
             // will skip the later part of this while
             i++;
@@ -873,8 +880,16 @@
             // if error is reasonable, add it into the results
             if (error < REPROJECTION_THREASHOLD) {
                 double [] rv = new double[3];
+                double timestamp;
+
                 rvec.get(0,0, rv);
-                recs.add(new AttitudeRec((double) i / meta.fps, rodr2rpy(rv)));
+                if (use_timestamp) {
+                    timestamp = (double)ts[0] / 1e6;
+                } else {
+                    timestamp = (double) i / meta.fps;
+                }
+                if (LOCAL_LOGV) Log.v(TAG, String.format("Added frame %d  ts = %f", i, timestamp));
+                recs.add(new AttitudeRec(timestamp, rodr2rpy(rv)));
             }
 
             if (OUTPUT_DEBUG_IMAGE) {
@@ -906,6 +921,8 @@
      * One issue right now is that the glReadPixels is quite slow .. around 6.5ms for a 720p frame
      */
     private class VideoDecoderForOpenCV implements Runnable {
+        static final String TAG = "VideoDecoderForOpenCV";
+
         private MediaExtractor extractor=null;
         private MediaCodec decoder=null;
         private CtsMediaOutputSurface surface=null;
@@ -1031,7 +1048,7 @@
             }
 
             if (decoder == null) {
-                Log.e("VideoDecoderForOpenCV", "Can't find video info!");
+                Log.e(TAG, "Can't find video info!");
                 return;
             }
             valid = true;
@@ -1060,6 +1077,7 @@
             long timeoutUs = 10000;
 
             int iframe = 0;
+            long frameTimestamp = 0;
 
             while (!Thread.interrupted()) {
                 if (!isEOS) {
@@ -1076,8 +1094,12 @@
                                     MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                             isEOS = true;
                         } else {
-                            decoder.queueInputBuffer(inIndex, 0, sampleSize,
-                                    extractor.getSampleTime(), 0);
+                            frameTimestamp = extractor.getSampleTime();
+                            decoder.queueInputBuffer(inIndex, 0, sampleSize, frameTimestamp, 0);
+                            if (LOCAL_LOGD) {
+                                Log.d(TAG, String.format("Frame %d sample time %f s",
+                                            iframe, (double)frameTimestamp/1e6));
+                            }
                             extractor.advance();
                         }
                     }
@@ -1088,19 +1110,19 @@
                 switch (outIndex) {
                     case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                         if (LOCAL_LOGD) {
-                            Log.d("VideoDecoderForOpenCV", "INFO_OUTPUT_BUFFERS_CHANGED");
+                            Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED");
                         }
                         outputBuffers = decoder.getOutputBuffers();
                         break;
                     case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                         outFormat = decoder.getOutputFormat();
                         if (LOCAL_LOGD) {
-                            Log.d("VideoDecoderForOpenCV", "New format " + outFormat);
+                            Log.d(TAG, "New format " + outFormat);
                         }
                         break;
                     case MediaCodec.INFO_TRY_AGAIN_LATER:
                         if (LOCAL_LOGD) {
-                            Log.d("VideoDecoderForOpenCV", "dequeueOutputBuffer timed out!");
+                            Log.d(TAG, "dequeueOutputBuffer timed out!");
                         }
                         break;
                     default:
@@ -1118,12 +1140,12 @@
                         if (doRender) {
                             surface.awaitNewImage();
                             surface.drawImage();
-                            if (LOCAL_LOGD) {
-                                Log.d("VideoDecoderForOpenCV", "Finish drawing a frame!");
+                            if (LOCAL_LOGV) {
+                                Log.v(TAG, "Finish drawing a frame!");
                             }
                             if ((iframe++ % mDecimation) == 0) {
                                 //Send the frame for processing
-                                mMatBuffer.put();
+                                mMatBuffer.put(frameTimestamp);
                             }
                         }
                         break;
@@ -1149,8 +1171,8 @@
          * Get next valid frame
          * @return Frame in OpenCV mat
          */
-        public Mat getFrame() {
-            return mMatBuffer.get();
+        public Mat getFrame(long ts[]) {
+            return mMatBuffer.get(ts);
         }
 
         /**
@@ -1168,6 +1190,7 @@
             private Mat mat;
             private byte[] bytes;
             private ByteBuffer buf;
+            private long timestamp;
             private boolean full;
 
             private int mWidth, mHeight;
@@ -1180,6 +1203,7 @@
                 mat = new Mat(height, width, CvType.CV_8UC4); //RGBA
                 buf = ByteBuffer.allocateDirect(width*height*4);
                 bytes = new byte[width*height*4];
+                timestamp = -1;
 
                 mValid = true;
                 full = false;
@@ -1190,7 +1214,7 @@
                 notifyAll();
             }
 
-            public synchronized Mat get() {
+            public synchronized Mat get(long ts[]) {
 
                 if (!mValid) return null;
                 while (full == false) {
@@ -1204,9 +1228,11 @@
                 mat.put(0,0, bytes);
                 full = false;
                 notifyAll();
+                ts[0] = timestamp;
                 return mat;
             }
-            public synchronized void put() {
+
+            public synchronized void put(long ts) {
                 while (full) {
                     try {
                         wait();
@@ -1219,6 +1245,7 @@
                 buf.get(bytes);
                 buf.rewind();
 
+                timestamp = ts;
                 full = true;
                 notifyAll();
             }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
index 9a74a0e..35c4d56 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
@@ -16,9 +16,10 @@
 
 package com.android.cts.verifier.sensors;
 
-
+import android.content.Context;
 import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
 import android.os.Bundle;
+import android.os.PowerManager;
 
 import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
 import com.android.cts.verifier.sensors.helpers.OpenCVLibrary;
@@ -82,7 +83,7 @@
 
         while(retry-->0) {
             try {
-                Thread.sleep(100);
+                Thread.sleep(250);
             } catch (InterruptedException e) {
                 //
             }
@@ -146,7 +147,15 @@
 
             // Analysis of recorded video and sensor data using RVCXAnalyzer
             RVCVXCheckAnalyzer analyzer = new RVCVXCheckAnalyzer(mRecPath);
+
+            // acquire a partial wake lock just in case CPU fall asleep
+            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                    "RVCVXCheckAnalyzer");
+
+            wl.acquire();
             mReport = analyzer.processDataSet();
+            wl.release();
 
             playSound();
             vibrate(500);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
index 6dbf8cc..2dfc7c8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
@@ -287,7 +287,9 @@
 
     @Override
     protected void activityCleanUp() {
-        mScreenManipulator.turnScreenOff();
+        if (mScreenManipulator != null) {
+            mScreenManipulator.turnScreenOff();
+        }
         LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCastReceiver);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
new file mode 100644
index 0000000..43f293a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.tv;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.media.tv.TvContract;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Tests for verifying TV app behavior for TV app-link.
+ */
+public class AppLinkTestActivity extends TvAppVerifierActivity implements View.OnClickListener {
+    private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
+
+    private boolean mSelectAppLinkItemPassed;
+    private View mSelectAppLinkItem;
+    private View mVerifyAppLinkIntentItem;
+    private View mVerifyAppLinkCardItem;
+
+    Runnable mSelectAppLinkFailCallback;
+
+    @Override
+    public void onClick(View v) {
+        final View postTarget = getPostTarget();
+
+        if (containsButton(mSelectAppLinkItem, v)) {
+            Intent tvAppIntent = null;
+            String[] projection = { TvContract.Channels._ID };
+            try (Cursor cursor = getContentResolver().query(
+                    TvContract.buildChannelsUriForInput(MockTvInputService.getInputId(this)),
+                    projection, null, null, null)) {
+                if (cursor != null && cursor.moveToNext()) {
+                    tvAppIntent = new Intent(Intent.ACTION_VIEW,
+                            TvContract.buildChannelUri(cursor.getLong(0)));
+                }
+            }
+            if (tvAppIntent == null) {
+                Toast.makeText(this, R.string.tv_channel_not_found, Toast.LENGTH_SHORT).show();
+                return;
+            }
+
+            mSelectAppLinkFailCallback = new Runnable() {
+                @Override
+                public void run() {
+                    mSelectAppLinkItemPassed = false;
+                    setPassState(mSelectAppLinkItem, false);
+                    setPassState(mVerifyAppLinkIntentItem, false);
+                }
+            };
+            postTarget.postDelayed(mSelectAppLinkFailCallback, TIMEOUT_MS);
+            mSelectAppLinkItemPassed = true;
+            setPassState(mSelectAppLinkItem, true);
+
+            startActivity(tvAppIntent);
+        } else if (containsButton(mVerifyAppLinkCardItem, v)) {
+            setPassState(mVerifyAppLinkCardItem, true);
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        if (mSelectAppLinkItemPassed
+                && TextUtils.equals(MockTvInputSetupActivity.APP_LINK_TEST_VALUE,
+                        intent.getStringExtra(MockTvInputSetupActivity.APP_LINK_TEST_KEY))) {
+            getPostTarget().removeCallbacks(mSelectAppLinkFailCallback);
+            setPassState(mVerifyAppLinkIntentItem, true);
+            setButtonEnabled(mVerifyAppLinkCardItem, true);
+        }
+    }
+
+    @Override
+    protected void createTestItems() {
+        mSelectAppLinkItem = createUserItem(R.string.tv_app_link_test_select_app_link,
+                R.string.tv_launch_tv_app, this);
+        setButtonEnabled(mSelectAppLinkItem, true);
+        mVerifyAppLinkIntentItem = createAutoItem(
+                R.string.tv_app_link_test_verify_link_clicked);
+        mVerifyAppLinkCardItem = createUserItem(R.string.tv_input_link_test_verify_link_interface,
+                android.R.string.yes, this);
+        TextView instructions = (TextView) mVerifyAppLinkCardItem.findViewById(R.id.instructions);
+        Drawable image = getDrawable(R.drawable.app_link_img);
+        image.setBounds(0, 0, 317, 241);
+        instructions.setCompoundDrawablePadding(10);
+        instructions.setCompoundDrawables(image, null, null, null);
+    }
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_app_link_test, R.string.tv_app_link_test_info, -1);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
index c05b753..43ed7da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
@@ -17,9 +17,12 @@
 package com.android.cts.verifier.tv;
 
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.ContentUris;
 import android.content.ContentValues;
+import android.content.Intent;
 import android.database.Cursor;
+import android.graphics.Color;
 import android.media.tv.TvContract;
 import android.media.tv.TvContract.Programs;
 import android.media.tv.TvInputInfo;
@@ -28,6 +31,8 @@
 import android.util.Pair;
 import android.view.View;
 
+import com.android.cts.verifier.R;
+
 import java.util.ArrayList;
 
 public class MockTvInputSetupActivity extends Activity {
@@ -38,6 +43,10 @@
 
     /* package-private */ static final String PROGRAM_TITLE = "Dummy Program";
     /* package-private */ static final String PROGRAM_DESCRIPTION = "Dummy Program Description";
+
+    /* package-private */ static final String APP_LINK_TEST_KEY = "app_link_test_key";
+    /* package-private */ static final String APP_LINK_TEST_VALUE = "app_link_test_value";
+    private static final String APP_LINK_TEXT = "Cts App-Link Text";
     private static final long PROGRAM_LENGTH_MILLIS = 60 * 60 * 1000;
     private static final int PROGRAM_COUNT = 24;
 
@@ -69,6 +78,18 @@
             values.put(TvContract.Channels.COLUMN_INPUT_ID, inputId);
             values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, CHANNEL_NUMBER);
             values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, CHANNEL_NAME);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_TEXT, APP_LINK_TEXT);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_COLOR, Color.RED);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_ICON_URI,
+                    "android.resource://" + getPackageName() + "/" + R.drawable.icon);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_POSTER_ART_URI,
+                    "android.resource://" + getPackageName() + "/" + R.raw.sns_texture);
+            Intent appLinkIntentUri = new Intent(this, AppLinkTestActivity.class);
+            appLinkIntentUri.putExtra(APP_LINK_TEST_KEY, APP_LINK_TEST_VALUE);
+            appLinkIntentUri.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_INTENT_URI,
+                    appLinkIntentUri.toUri(Intent.URI_INTENT_SCHEME));
+
             Uri channelUri = getContentResolver().insert(uri, values);
             // If the channel's ID happens to be zero, we add another and delete the one.
             if (ContentUris.parseId(channelUri) == 0) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
index 12e9652..acab18e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -35,8 +35,6 @@
 public abstract class TvAppVerifierActivity extends PassFailButtons.Activity {
     private static final String TAG = "TvAppVerifierActivity";
 
-    private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
-
     private LayoutInflater mInflater;
     private ViewGroup mItemList;
     private View mPostTarget;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
index 06f4f6f..e8e2cee 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -25,8 +25,6 @@
 
 import com.android.cts.verifier.R;
 
-import java.util.List;
-
 /**
  * Tests for verifying TV app behavior for third-party TV input apps.
  */
@@ -131,7 +129,7 @@
         mGoToEpgItem = createUserItem(R.string.tv_input_discover_test_go_to_epg,
                 R.string.tv_launch_epg, this);
         mVerifyEpgItem = createUserItem(R.string.tv_input_discover_test_verify_epg,
-                R.string.tv_input_discover_test_yes, this);
+                android.R.string.yes, this);
     }
 
     @Override
diff --git a/apps/cts-usb-accessory/Android.mk b/apps/cts-usb-accessory/Android.mk
index 8d18da3..f3a7ebd 100644
--- a/apps/cts-usb-accessory/Android.mk
+++ b/apps/cts-usb-accessory/Android.mk
@@ -33,6 +33,7 @@
 LOCAL_STATIC_LIBRARIES := libusbhost libcutils
 LOCAL_LDLIBS += -lpthread
 LOCAL_CFLAGS := -g -O0
+LOCAL_CXX_STL := none
 
 include $(BUILD_HOST_EXECUTABLE)
 
diff --git a/build/test_deqp_package.mk b/build/test_deqp_package.mk
index 8fbae26..650875c 100644
--- a/build/test_deqp_package.mk
+++ b/build/test_deqp_package.mk
@@ -18,15 +18,14 @@
 
 CTS_DEQP_CONFIG_PATH := $(call my-dir)
 
-cts_library_xml := $(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(DEQP_API).xml
-$(cts_library_xml): MUSTPASS_XML_FILE := external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml
-$(cts_library_xml): PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
-$(cts_library_xml): PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
-$(cts_library_xml): PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
-$(cts_library_xml): external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
-	$(hide) echo Generating test description for $(PRIVATE_TEST_NAME)
+cts_library_xmls:=$(foreach xml_file, $(call find-files-in-subdirs, external/deqp/android/cts/master, 'com.drawelements.deqp.$(DEQP_API).*xml', .), $(CTS_TESTCASES_OUT)/$(xml_file))
+$(cts_library_xmls) : PRIVATE_API := $(DEQP_API)
+$(cts_library_xmls) : PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
+$(cts_library_xmls) : PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
+$(cts_library_xmls) : PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
+$(cts_library_xmls) : $(CTS_TESTCASES_OUT)/%.xml: external/deqp/android/cts/master/%.xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
+	$(hide) echo Generating test description $@
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
-
 # Query build ABIs by routing a dummy test list through xml generator and parse result
 	$(hide) $(eval supported_abi_attr := $(shell $(CTS_XML_GENERATOR) -t dummyTest \
 										-n dummyName \
@@ -36,8 +35,7 @@
 										-a $(CTS_TARGET_ARCH) \
 										< $(PRIVATE_DUMMY_CASELIST) \
 										| grep --only-matching -e " abis=\"[^\"]*\""))
-
 # Patch xml caselist with supported abi
 	$(hide) $(SED_EXTENDED) -e 's:^(\s*)<Test ((.[^/]|[^/])*)(/?)>$$:\1<Test \2 $(supported_abi_attr)\4>:' \
-				< $(MUSTPASS_XML_FILE) \
+				< $< \
 				> $@
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
index f3af0bc..2f80911 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
@@ -25,19 +25,37 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * An instrumentation that runs all activities that extends DeviceInfoActivity.
  */
 public class DeviceInfoInstrument extends Instrumentation {
 
     private static final String LOG_TAG = "ExtendedDeviceInfo";
-    private static final int DEVICE_INFO_ACTIVITY_REQUEST = 1;
+    private static final String COLLECTOR = "collector";
 
+    // List of collectors to run. If null or empty, all collectors will run.
+    private Set<String> mCollectorSet = new HashSet<String>();
+
+    // Results sent to the caller when this istrumentation completes.
     private Bundle mBundle = new Bundle();
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            String collectorList = savedInstanceState.getString(COLLECTOR);
+            if (!TextUtils.isEmpty(collectorList)) {
+                for (String collector : TextUtils.split(collectorList, ",")) {
+                  if (!TextUtils.isEmpty(collector)) {
+                    mCollectorSet.add(collector);
+                  }
+                }
+            }
+        }
         start();
     }
 
@@ -47,13 +65,8 @@
             Context context = getContext();
             ActivityInfo[] activities = context.getPackageManager().getPackageInfo(
                     context.getPackageName(), PackageManager.GET_ACTIVITIES).activities;
-
             for (ActivityInfo activityInfo : activities) {
-                Class cls = Class.forName(activityInfo.name);
-                if (cls != DeviceInfoActivity.class &&
-                        DeviceInfoActivity.class.isAssignableFrom(cls)) {
-                    runActivity(activityInfo.name);
-                }
+                runActivity(activityInfo.name);
             }
         } catch (Exception e) {
             Log.e(LOG_TAG, "Exception occurred while running activities.", e);
@@ -65,9 +78,40 @@
     }
 
     /**
+     * Returns true if the activity meets the criteria to run; otherwise, false.
+     */
+    private boolean isActivityRunnable(Class activityClass) {
+        // Don't run the base DeviceInfoActivity class.
+        if (DeviceInfoActivity.class == activityClass) {
+            return false;
+        }
+        // Don't run anything that doesn't extends DeviceInfoActivity.
+        if (!DeviceInfoActivity.class.isAssignableFrom(activityClass)) {
+            return false;
+        }
+        // Only run activity if mCollectorSet is empty or contains it.
+        if (mCollectorSet != null && mCollectorSet.size() > 0) {
+            return mCollectorSet.contains(activityClass.getName());
+        }
+        // Run anything that makes it here.
+        return true;
+    }
+
+    /**
      * Runs a device info activity and return the file path where the results are written to.
      */
     private void runActivity(String activityName) throws Exception {
+        Class activityClass = null;
+        try {
+            activityClass = Class.forName(activityName);
+        } catch (ClassNotFoundException e) {
+            return;
+        }
+
+        if (activityClass == null || !isActivityRunnable(activityClass)) {
+            return;
+        }
+
         Intent intent = new Intent();
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setClassName(this.getContext(), activityName);
@@ -76,7 +120,7 @@
         waitForIdleSync();
         activity.waitForActivityToFinish();
 
-        String className = Class.forName(activityName).getSimpleName();
+        String className = activityClass.getSimpleName();
         String errorMessage = activity.getErrorMessage();
         if (TextUtils.isEmpty(errorMessage)) {
             mBundle.putString(className, activity.getResultFilePath());
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
index f6e7c57..decf6dd 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
@@ -68,6 +68,8 @@
     public static final String BUILD_SERIAL = "build_serial";
     public static final String BUILD_VERSION_RELEASE = "build_version_release";
     public static final String BUILD_VERSION_SDK = "build_version_sdk";
+    public static final String BUILD_VERSION_BASE_OS = "build_version_base_os";
+    public static final String BUILD_VERSION_SECURITY_PATH = "build_version_security_patch";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -93,5 +95,7 @@
         addResult(BUILD_SERIAL, Build.SERIAL);
         addResult(BUILD_VERSION_RELEASE, Build.VERSION.RELEASE);
         addResult(BUILD_VERSION_SDK, Build.VERSION.SDK);
+        addResult(BUILD_VERSION_BASE_OS, Build.VERSION.BASE_OS);
+        addResult(BUILD_VERSION_SECURITY_PATH, Build.VERSION.SECURITY_PATCH);
     }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
index 70414ca..2ae2e10 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
@@ -294,7 +294,7 @@
     private LocalVolumeInfo getAdoptionVolume() throws Exception {
         String[] lines = null;
         int attempt = 0;
-        while (attempt++ < 5) {
+        while (attempt++ < 15) {
             lines = getDevice().executeShellCommand("sm list-volumes private").split("\n");
             for (String line : lines) {
                 final LocalVolumeInfo info = new LocalVolumeInfo(line.trim());
diff --git a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
index a86f7f0..c460300 100644
--- a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
+++ b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
@@ -19,7 +19,7 @@
     A simple app with a tracing section to test that apps tracing signals are
     emitted by atrace.
     -->
-    <application>
+    <application android:debuggable="true"> <!-- Debuggable to enable tracing -->
         <activity android:name=".AtraceTestAppActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index c8a2d8e..760723e 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -209,7 +209,7 @@
 
             // capture a launch of the app with async tracing
             // content traced by 'view' tag tested below, 'sched' used to ensure tgid printed
-            String atraceArgs = "-a " + TEST_PKG + " -c -b 16000 view sched"; // TODO: zipping
+            String atraceArgs = "-a " + TEST_PKG + " -c -b 16000 view"; // TODO: zipping
             getDevice().executeShellCommand("atrace --async_stop " + atraceArgs);
             getDevice().executeShellCommand("atrace --async_start " + atraceArgs);
             getDevice().executeShellCommand("am start " + TEST_PKG);
@@ -228,13 +228,15 @@
         String traceData = atraceOutput.substring(dataStart + MARKER.length());
 
         FtraceEntryCallback callback = new FtraceEntryCallback() {
-            private int matches = 0;
-            private int nextSectionIndex = 0;
-            private int appPid = -1;
+            private int userSpaceMatches = 0;
+            private int beginMatches = 0;
+            private int nextSectionIndex = -1;
+            private int appTid = -1;
 
-            // list of tags expected to be seen on app launch, in order.
+
+            private final String initialSection = "traceable-app-test-section";
+            // list of tags expected to be seen on app launch, in order, after the initial.
             private final String[] requiredSectionList = {
-                    "traceable-app-test-section",
                     "inflate",
                     "Choreographer#doFrame",
                     "traversal",
@@ -252,34 +254,41 @@
                     return;
                 }
 
-                matches++;
                 assertNotNull(truncatedThreadName);
                 assertTrue(tid > 0);
-                if (TEST_PKG.endsWith(truncatedThreadName)) {
-                    matches++;
+                userSpaceMatches++;
 
-                    if (pid >= 0) {
-                        // verify pid, if present
-                        if (appPid == -1) {
-                            appPid = pid;
-                        } else {
-                            assertEquals(appPid, pid);
-                        }
-                    }
+                if (details == null || !details.startsWith("B|")) {
+                    // not a begin event
+                    return;
+                }
+                beginMatches++;
 
-                    if (nextSectionIndex < requiredSectionList.length
-                            && details != null
-                            && details.startsWith("B|")
-                            && details.endsWith("|" + requiredSectionList[nextSectionIndex])) {
-                        nextSectionIndex++;
-                    }
+                if (details.endsWith("|" + initialSection)) {
+                    // initial section observed, start looking for others in order
+                    assertEquals(nextSectionIndex, -1);
+                    nextSectionIndex = 0;
+                    appTid = tid;
+                    return;
+                }
+
+                if (nextSectionIndex >= 0
+                        && tid == appTid
+                        && nextSectionIndex < requiredSectionList.length
+                        && details.endsWith("|" + requiredSectionList[nextSectionIndex])) {
+                    // found next required section in sequence
+                    nextSectionIndex++;
                 }
             }
 
             @Override
             public void onFinished() {
                 assertTrue("Unable to parse any userspace sections from atrace output",
-                        matches != 0);
+                        userSpaceMatches != 0);
+                assertTrue("Unable to parse any section begin events from atrace output",
+                        beginMatches != 0);
+                assertTrue("Unable to parse initial userspace sections from test app",
+                        nextSectionIndex >= 0);
                 assertEquals("Didn't see required list of traced sections, in order",
                         requiredSectionList.length, nextSectionIndex);
             }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
index 6e520c3..fe07bcb 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
@@ -71,6 +71,13 @@
                        android:resource="@xml/authenticator" />
         </service>
 
+        <activity android:name=".UserRestrictionActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java
new file mode 100644
index 0000000..fed1a79
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.deviceandprofileowner;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Process;
+import android.util.Log;
+
+/**
+ * Simple activity that adds or clears a user restriction depending on the value of the extras.
+ */
+public class UserRestrictionActivity extends Activity {
+
+    private static final String TAG = UserRestrictionActivity.class.getName();
+
+    private static final String EXTRA_RESTRICTION_KEY = "extra-restriction-key";
+    private static final String EXTRA_COMMAND = "extra-command";
+
+    private static final String ADD_COMMAND = "add-restriction";
+    private static final String CLEAR_COMMAND = "clear-restriction";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        handleIntent(getIntent());
+    }
+
+    // Overriding this method in case another intent is sent to this activity before finish()
+    @Override
+    public void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        handleIntent(intent);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        // Calling finish() here because doing it in onCreate(), onStart() or onResume() makes
+        // "adb shell am start" timeout if using the -W option.
+        finish();
+    }
+
+    private void handleIntent(Intent intent) {
+        DevicePolicyManager dpm = (DevicePolicyManager)
+                getSystemService(Context.DEVICE_POLICY_SERVICE);
+        String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION_KEY);
+        String command = intent.getStringExtra(EXTRA_COMMAND);
+        Log.i(TAG, "Command: \"" + command + "\". Restriction: \"" + restrictionKey + "\"");
+
+        if (ADD_COMMAND.equals(command)) {
+            dpm.addUserRestriction(BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+            Log.i(TAG, "Added user restriction " + restrictionKey
+                    + " for user " + Process.myUserHandle());
+        } else if (CLEAR_COMMAND.equals(command)) {
+            dpm.clearUserRestriction(
+                    BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+            Log.i(TAG, "Cleared user restriction " + restrictionKey
+                    + " for user " + Process.myUserHandle());
+        } else {
+            Log.e(TAG, "Invalid command: " + command);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
index 9127dab..51c575c 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
@@ -15,69 +15,143 @@
  */
 package com.android.cts.deviceowner;
 
-import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
-
 import java.io.ByteArrayInputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
-import java.security.cert.Certificate;
+import java.util.Arrays;
 import java.util.List;
 
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
+import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
+
 public class CaCertManagementTest extends BaseDeviceOwnerTest {
+    /**
+     * Test: device admins should be able to list all installed certs.
+     *
+     * <p>The list of certificates must never be {@code null}.
+     */
     public void testCanRetrieveListOfInstalledCaCerts() {
         List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(getWho());
         assertNotNull(caCerts);
     }
 
+    /**
+     * Test: a valid cert should be installable and also removable.
+     */
     public void testCanInstallAndUninstallACaCert()
-    throws CertificateException {
-        assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
-        assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+            throws CertificateException, GeneralSecurityException {
+        assertUninstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+
         assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
-        assertTrue(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
-        assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+        assertInstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+
         mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
-        assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
-        assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+        assertUninstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
     }
 
-    public void testUninstallationIsSelective() throws CertificateException {
+    /**
+     * Test: removing one certificate must not remove any others.
+     */
+    public void testUninstallationIsSelective()
+            throws CertificateException, GeneralSecurityException {
         assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
         assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+
         mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_DSA_1.caCertificate);
-        assertTrue(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
-        assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+        assertInstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+
         mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
     }
 
-    public void testCanUninstallAllUserCaCerts() throws CertificateException {
+    /**
+     * Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
+     * supplementary installed certificate.
+     */
+    public void testCanUninstallAllUserCaCerts()
+            throws CertificateException, GeneralSecurityException {
         assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
         assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+
         mDevicePolicyManager.uninstallAllUserCaCerts(getWho());
-        assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
-        assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+        assertUninstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
     }
 
-    private boolean hasCaCertInstalled(byte [] caCert) throws CertificateException {
-        boolean result = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert);
-        assertEquals(result, containsCertificate(
-            mDevicePolicyManager.getInstalledCaCerts(getWho()), caCert));
-        return result;
+    private void assertInstalled(byte[] caBytes)
+            throws CertificateException, GeneralSecurityException {
+        Certificate caCert = readCertificate(caBytes);
+        assertTrue(isCaCertInstalledAndTrusted(caCert));
     }
 
-    private static boolean containsCertificate(List<byte[]> certificates, byte [] toMatch)
-            throws CertificateException {
-        Certificate certificateToMatch = readCertificate(toMatch);
-        for (byte[] certBuffer : certificates) {
-            Certificate cert = readCertificate(certBuffer);
-            if (certificateToMatch.equals(cert)) {
-                return true;
+    private void assertUninstalled(byte[] caBytes)
+            throws CertificateException, GeneralSecurityException {
+        Certificate caCert = readCertificate(caBytes);
+        assertFalse(isCaCertInstalledAndTrusted(caCert));
+    }
+
+    /**
+     * Whether a given cert, or one a lot like it, has been installed system-wide and is available
+     * to all apps.
+     *
+     * <p>A CA certificate is "installed" if it matches all of the following conditions:
+     * <ul>
+     *   <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
+     *   <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
+     *       necessarily exactly the same) in its response.</li>
+     *   <li>Any new instances of {@link TrustManager} should report the certificate among their
+     *       accepted issuer list -- older instances may keep the set of issuers they were created
+     *       with until explicitly refreshed.</li>
+     *
+     * @return {@code true} if installed by all metrics, {@code false} if not installed by any
+     *         metric. In any other case an {@link AssertionError} will be thrown.
+     */
+    private boolean isCaCertInstalledAndTrusted(Certificate caCert)
+            throws GeneralSecurityException, CertificateException {
+        boolean installed = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert.getEncoded());
+
+        boolean listed = false;
+        for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(getWho())) {
+            if (caCert.equals(readCertificate(certBuffer))) {
+                listed = true;
             }
         }
-        return false;
+
+        boolean trusted = false;
+        final TrustManagerFactory tmf =
+                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        tmf.init((KeyStore) null);
+        for (TrustManager trustManager : tmf.getTrustManagers()) {
+             if (trustManager instanceof X509TrustManager) {
+                final X509TrustManager tm = (X509TrustManager) trustManager;
+                if (Arrays.asList(tm.getAcceptedIssuers()).contains(caCert)) {
+                    trusted = true;
+                }
+            }
+        }
+
+        // All three responses should match - if an installed certificate isn't trusted or (worse)
+        // a trusted certificate isn't even installed we should 
+        assertEquals(installed, listed);
+        assertEquals(installed, trusted);
+        return installed;
     }
 
+    /**
+     * Convert an encoded certificate back into a {@link Certificate}.
+     *
+     * Instantiates a fresh CertificateFactory every time for repeatability.
+     */
     private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
         final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
         return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
new file mode 100644
index 0000000..e68c884
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsPackageInstallerApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctstestrunner ub-uiautomator
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml b/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml
new file mode 100644
index 0000000..aaa88f2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.packageinstaller">
+
+    <uses-sdk android:minSdkVersion="21"/>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <receiver
+            android:name=".ClearDeviceOwnerTest$BasicAdminReceiver"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                       android:resource="@xml/device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.cts.packageinstaller"
+        android:label="Package Installer CTS Tests" />
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml b/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml
new file mode 100644
index 0000000..de4a9e1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml
@@ -0,0 +1,3 @@
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+    <uses-policies />
+</device-admin>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
similarity index 70%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
rename to hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
index 0eddbee..f994e9e 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
@@ -13,17 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.deviceowner;
+package com.android.cts.packageinstaller;
 
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.support.test.uiautomator.UiDevice;
+import android.test.InstrumentationTestCase;
+
+import com.android.cts.packageinstaller.ClearDeviceOwnerTest.BasicAdminReceiver;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -31,34 +37,41 @@
 import java.io.OutputStream;
 
 /**
- * This class tests silent package install and uninstall by a device owner.
+ * Base test case for testing PackageInstaller.
  */
-public class PackageInstallTest extends BaseDeviceOwnerTest {
-    private static final String TEST_APP_LOCATION = "/data/local/tmp/CtsSimpleApp.apk";
-    private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
-    private static final int PACKAGE_INSTALLER_TIMEOUT_MS = 60000; // 60 seconds
+public class BasePackageInstallTest extends InstrumentationTestCase {
+    protected static final String TEST_APP_LOCATION = "/data/local/tmp/CtsSimpleApp.apk";
+    protected static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+    protected static final int PACKAGE_INSTALLER_TIMEOUT_MS = 60000; // 60 seconds
     private static final String ACTION_INSTALL_COMMIT =
             "com.android.cts.deviceowner.INTENT_PACKAGE_INSTALL_COMMIT";
-    private static final int PACKAGE_INSTALLER_STATUS_UNDEFINED = -1000;
+    protected static final int PACKAGE_INSTALLER_STATUS_UNDEFINED = -1000;
+    public static final String PACKAGE_NAME = SilentPackageInstallTest.class.getPackage().getName();
 
+    protected Context mContext;
+    protected UiDevice mDevice;
+    protected DevicePolicyManager mDevicePolicyManager;
     private PackageManager mPackageManager;
     private PackageInstaller mPackageInstaller;
     private PackageInstaller.Session mSession;
-    private boolean mCallbackReceived;
-    private int mCallbackStatus;
+    protected boolean mCallbackReceived;
+    protected int mCallbackStatus;
+    protected Intent mCallbackIntent;
 
-    private final Object mPackageInstallerTimeoutLock = new Object();
+    protected final Object mPackageInstallerTimeoutLock = new Object();
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            mContext.unregisterReceiver(this);
             synchronized (mPackageInstallerTimeoutLock) {
                 mCallbackStatus = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
                         PACKAGE_INSTALLER_STATUS_UNDEFINED);
                 if (mCallbackStatus == PackageInstaller.STATUS_SUCCESS) {
+                    mContext.unregisterReceiver(this);
                     assertEquals(TEST_APP_PKG, intent.getStringExtra(
                             PackageInstaller.EXTRA_PACKAGE_NAME));
+                } else if (mCallbackStatus == PackageInstaller.STATUS_PENDING_USER_ACTION) {
+                    mCallbackIntent = (Intent) intent.getExtras().get(Intent.EXTRA_INTENT);
                 }
                 mCallbackReceived = true;
                 mPackageInstallerTimeoutLock.notify();
@@ -69,6 +82,10 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        mContext = getInstrumentation().getContext();
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        mDevicePolicyManager = (DevicePolicyManager)
+                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mPackageManager = mContext.getPackageManager();
         mPackageInstaller = mPackageManager.getPackageInstaller();
         assertNotNull(mPackageInstaller);
@@ -79,7 +96,10 @@
 
     @Override
     protected void tearDown() throws Exception {
-        mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+        if (mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME) ||
+                mDevicePolicyManager.isProfileOwnerApp(PACKAGE_NAME)) {
+            mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+        }
         try {
             mContext.unregisterReceiver(mBroadcastReceiver);
         } catch (IllegalArgumentException e) {
@@ -91,33 +111,12 @@
         super.tearDown();
     }
 
-    public void testSilentInstallUninstall() throws Exception {
-        // install the app
-        assertInstallPackage();
-
-        // uninstall the app again
-        assertTrue(tryUninstallPackage());
-        assertFalse(isPackageInstalled(TEST_APP_PKG));
+    protected static ComponentName getWho() {
+        return new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName());
     }
 
-    public void testUninstallBlocked() throws Exception {
-        // install the app
-        assertInstallPackage();
-
-        mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, true);
-        assertTrue(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
-        assertTrue(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
-        assertFalse(tryUninstallPackage());
-        assertTrue(isPackageInstalled(TEST_APP_PKG));
-
-        mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
-        assertFalse(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
-        assertFalse(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
-        assertTrue(tryUninstallPackage());
+    protected void assertInstallPackage() throws Exception {
         assertFalse(isPackageInstalled(TEST_APP_PKG));
-    }
-
-    private void assertInstallPackage() throws Exception {
         synchronized (mPackageInstallerTimeoutLock) {
             mCallbackReceived = false;
             mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
@@ -134,7 +133,7 @@
         assertTrue(isPackageInstalled(TEST_APP_PKG));
     }
 
-    private boolean tryUninstallPackage() throws Exception {
+    protected boolean tryUninstallPackage() throws Exception {
         assertTrue(isPackageInstalled(TEST_APP_PKG));
         synchronized (mPackageInstallerTimeoutLock) {
             mCallbackReceived = false;
@@ -151,7 +150,7 @@
         }
     }
 
-    private void installPackage(String packageLocation) throws Exception {
+    protected void installPackage(String packageLocation) throws Exception {
         PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                 PackageInstaller.SessionParams.MODE_FULL_INSTALL);
         int sessionId = mPackageInstaller.createSession(params);
@@ -184,11 +183,11 @@
                 mContext,
                 sessionId,
                 broadcastIntent,
-                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT);
         return pendingIntent.getIntentSender();
     }
 
-    private boolean isPackageInstalled(String packageName) {
+    protected boolean isPackageInstalled(String packageName) {
         try {
             PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
             return pi != null;
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java
new file mode 100644
index 0000000..a06271b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.packageinstaller;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Base class for profile and device based tests.
+ *
+ * This class handles making sure that the test is the profile or device owner and that it has an
+ * active admin registered, so that all tests may assume these are done.
+ */
+public class ClearDeviceOwnerTest extends InstrumentationTestCase {
+
+    public static class BasicAdminReceiver extends DeviceAdminReceiver {
+    }
+
+    public static final String PACKAGE_NAME = BasicAdminReceiver.class.getPackage().getName();
+    public static final ComponentName ADMIN_RECEIVER_COMPONENT = new ComponentName(
+            PACKAGE_NAME, BasicAdminReceiver.class.getName());
+
+    private DevicePolicyManager mDevicePolicyManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevicePolicyManager = (DevicePolicyManager)
+                getInstrumentation().getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
+        assertNotNull(mDevicePolicyManager);
+
+        assertTrue(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
+        assertTrue("App is not device owner", mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        removeActiveAdmin(ADMIN_RECEIVER_COMPONENT);
+        mDevicePolicyManager.clearDeviceOwnerApp(PACKAGE_NAME);
+        assertFalse(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
+        assertFalse(mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+
+        super.tearDown();
+    }
+
+    // This test clears the device owner and active admin on tearDown(). To be called from the host
+    // side test once a test case is finished.
+    public void testClearDeviceOwner() {
+    }
+
+    private void removeActiveAdmin(ComponentName cn) throws InterruptedException {
+        if (mDevicePolicyManager.isAdminActive(cn)) {
+            mDevicePolicyManager.removeActiveAdmin(cn);
+            for (int i = 0; i < 1000 && mDevicePolicyManager.isAdminActive(cn); i++) {
+                Thread.sleep(100);
+            }
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
new file mode 100644
index 0000000..96affae
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.packageinstaller;
+
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+/**
+ * This class tests manual package install and uninstall by a device owner.
+ */
+public class ManualPackageInstallTest extends BasePackageInstallTest {
+    private static final int AUTOMATOR_WAIT_TIMEOUT = 5000;
+    private static final int INSTALL_WAIT_TIME = 5000;
+
+    private static final BySelector POPUP_BUTTON_SELECTOR = By
+            .clazz(android.widget.Button.class.getName())
+            .res("android:id/button1")
+            .pkg("com.google.android.packageinstaller");
+    private static final BySelector POPUP_TEXT_SELECTOR = By
+            .clazz(android.widget.TextView.class.getName())
+            .res("android:id/alertTitle")
+            .pkg("com.google.android.packageinstaller");
+    private static final BySelector INSTALL_BUTTON_SELECTOR = By
+            .clazz(android.widget.Button.class.getName())
+            .res("com.android.packageinstaller:id/ok_button")
+            .pkg("com.google.android.packageinstaller");
+
+    public void testManualInstallSucceeded() throws Exception {
+        assertInstallPackage();
+    }
+
+    public void testManualInstallBlocked() throws Exception {
+        synchronized (mPackageInstallerTimeoutLock) {
+            mCallbackReceived = false;
+            mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
+        }
+        // Calls the original installPackage which does not click through the install button.
+        super.installPackage(TEST_APP_LOCATION);
+        synchronized (mPackageInstallerTimeoutLock) {
+            try {
+                mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
+            } catch (InterruptedException e) {
+            }
+            assertTrue(mCallbackReceived);
+            assertEquals(PackageInstaller.STATUS_PENDING_USER_ACTION, mCallbackStatus);
+        }
+
+        mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(mCallbackIntent);
+
+        automateDismissInstallBlockedDialog();
+
+        // Assuming installation is not synchronous, we should wait a while before checking.
+        Thread.sleep(INSTALL_WAIT_TIME);
+        assertFalse(isPackageInstalled(TEST_APP_PKG));
+    }
+
+    @Override
+    protected void installPackage(String packageLocation) throws Exception {
+        super.installPackage(packageLocation);
+
+        synchronized (mPackageInstallerTimeoutLock) {
+            try {
+                mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
+            } catch (InterruptedException e) {
+            }
+            assertTrue(mCallbackReceived);
+            assertEquals(PackageInstaller.STATUS_PENDING_USER_ACTION, mCallbackStatus);
+        }
+
+        // Use a receiver to listen for package install.
+        synchronized (mPackageInstallerTimeoutLock) {
+            mCallbackReceived = false;
+            mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
+        }
+
+        mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(mCallbackIntent);
+
+        automateInstallClick();
+    }
+
+    private void automateInstallClick() {
+        mDevice.wait(Until.hasObject(INSTALL_BUTTON_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
+        UiObject2 button = mDevice.findObject(INSTALL_BUTTON_SELECTOR);
+        assertNotNull("Install button not found", button);
+        button.click();
+    }
+
+    private void automateDismissInstallBlockedDialog() {
+        mDevice.wait(Until.hasObject(POPUP_TEXT_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
+        UiObject2 text = mDevice.findObject(POPUP_TEXT_SELECTOR);
+        assertNotNull("Alert dialog not found", text);
+        // "OK" button only present in the dialog if it is blocked by policy.
+        UiObject2 button = mDevice.findObject(POPUP_BUTTON_SELECTOR);
+        assertNotNull("OK button not found", button);
+        button.click();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java
new file mode 100644
index 0000000..f1a80b9
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.packageinstaller;
+
+/**
+ * This class tests silent package install and uninstall by a device owner.
+ */
+public class SilentPackageInstallTest extends BasePackageInstallTest {
+    public void testSilentInstallUninstall() throws Exception {
+        // install the app
+        assertInstallPackage();
+
+        // uninstall the app again
+        assertTrue(tryUninstallPackage());
+        assertFalse(isPackageInstalled(TEST_APP_PKG));
+    }
+
+    public void testUninstallBlocked() throws Exception {
+        // install the app
+        assertInstallPackage();
+
+        mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, true);
+        assertTrue(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
+        assertTrue(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
+        assertFalse(tryUninstallPackage());
+        assertTrue(isPackageInstalled(TEST_APP_PKG));
+
+        mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+        assertFalse(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
+        assertFalse(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
+        assertTrue(tryUninstallPackage());
+        assertFalse(isPackageInstalled(TEST_APP_PKG));
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 650e963..4fc14e4 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -17,7 +17,6 @@
 package com.android.cts.devicepolicy;
 
 import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.InstrumentationResultParser;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -363,4 +362,20 @@
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
         return commandOutput.startsWith("Success:");
     }
+
+    protected String getSettings(String namespace, String name, int userId)
+            throws DeviceNotAvailableException {
+        String command = "settings --user " + userId + " get " + namespace + " " + name;
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+        return commandOutput.replace("\n", "").replace("\r", "");
+    }
+
+    protected void putSettings(String namespace, String name, String value, int userId)
+            throws DeviceNotAvailableException {
+        String command = "settings --user " + userId + " put " + namespace + " " + name
+                + " " + value;
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 7cb8f3b..8d22638 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,9 +16,7 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
+import java.io.File;
 import java.lang.Exception;
 
 /**
@@ -49,6 +47,18 @@
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
     private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
+    private static final String TEST_APP_APK = "CtsSimpleApp.apk";
+    private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+    private static final String TEST_APP_LOCATION = "/data/local/tmp/";
+
+    private static final String PACKAGE_INSTALLER_PKG = "com.android.cts.packageinstaller";
+    private static final String PACKAGE_INSTALLER_APK = "CtsPackageInstallerApp.apk";
+    private static final String PACKAGE_INSTALLER_ADMIN_COMPONENT =
+            PACKAGE_INSTALLER_PKG + "/" + ".ClearDeviceOwnerTest$BasicAdminReceiver";
+    private static final String PACKAGE_INSTALLER_CLEAR_DEVICE_OWNER_TEST_CLASS =
+            PACKAGE_INSTALLER_PKG + ".ClearDeviceOwnerTest";
+
+    @Override
     public void tearDown() throws Exception {
         if (mHasFeature) {
             getDevice().uninstallPackage(DEVICE_OWNER_PKG);
@@ -117,4 +127,28 @@
                     "testRemoveAccounts", 0));
         }
     }
+
+    public void testSilentPackageInstall() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+        try {
+            // Install the test and prepare the test apk.
+            installApp(PACKAGE_INSTALLER_APK);
+            assertTrue(setDeviceOwner(PACKAGE_INSTALLER_ADMIN_COMPONENT));
+
+            getDevice().uninstallPackage(TEST_APP_PKG);
+            assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
+            assertTrue(runDeviceTests(PACKAGE_INSTALLER_PKG,
+                    PACKAGE_INSTALLER_PKG + ".SilentPackageInstallTest"));
+        } finally {
+            assertTrue("Failed to remove device owner.", runDeviceTests(PACKAGE_INSTALLER_PKG,
+                    PACKAGE_INSTALLER_CLEAR_DEVICE_OWNER_TEST_CLASS));
+            String command = "rm " + TEST_APP_LOCATION + apk.getName();
+            String commandOutput = getDevice().executeShellCommand(command);
+            getDevice().uninstallPackage(TEST_APP_PKG);
+            getDevice().uninstallPackage(PACKAGE_INSTALLER_PKG);
+        }
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 439c85f..43e6730 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -20,6 +20,8 @@
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 
+import java.io.File;
+
 /**
  * Set of tests for usecases that apply to profile and device owner.
  * This class is the base class of MixedProfileOwnerTest and MixedDeviceOwnerTest and is abstract
@@ -41,8 +43,18 @@
     private static final String CERT_INSTALLER_PKG = "com.android.cts.certinstaller";
     private static final String CERT_INSTALLER_APK = "CtsCertInstallerApp.apk";
 
+    private static final String TEST_APP_APK = "CtsSimpleApp.apk";
+    private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+    private static final String TEST_APP_LOCATION = "/data/local/tmp/";
+
+    private static final String PACKAGE_INSTALLER_PKG = "com.android.cts.packageinstaller";
+    private static final String PACKAGE_INSTALLER_APK = "CtsPackageInstallerApp.apk";
+
     protected static final int USER_OWNER = 0;
 
+    private static final String ADD_RESTRICTION_COMMAND = "add-restriction";
+    private static final String CLEAR_RESTRICTION_COMMAND = "clear-restriction";
+
     // ID of the user all tests are run as. For device owner this will be 0, for profile owner it
     // is the user id of the created profile.
     protected int mUserId;
@@ -167,7 +179,6 @@
         executeDeviceTestClass(".ApplicationHiddenTest");
     }
 
-    // TODO: Remove AccountManagementTest from XTS after GTS is released for MNC.
     public void testAccountManagement() throws Exception {
         if (!mHasFeature) {
             return;
@@ -206,6 +217,49 @@
         }
     }
 
+    public void testPackageInstallUserRestrictions() throws Exception {
+        // UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES
+        final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
+        final String UNKNOWN_SOURCES_SETTING = "install_non_market_apps";
+        final String SECURE_SETTING_CATEGORY = "secure";
+        final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+        String unknownSourceSetting = null;
+        try {
+            // Install the test and prepare the test apk.
+            installApp(PACKAGE_INSTALLER_APK);
+            assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
+
+            // Add restrictions and test if we can install the apk.
+            getDevice().uninstallPackage(TEST_APP_PKG);
+            changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
+                    ADD_RESTRICTION_COMMAND, mUserId);
+            assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+                    "testManualInstallBlocked", mUserId));
+
+            // Clear restrictions and test if we can install the apk.
+            changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
+                    CLEAR_RESTRICTION_COMMAND, mUserId);
+
+            // Enable Unknown sources in Settings.
+            unknownSourceSetting =
+                    getSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, mUserId);
+            putSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, "1", mUserId);
+            assertEquals("1",
+                    getSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, mUserId));
+            assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+                    "testManualInstallSucceeded", mUserId));
+        } finally {
+            String command = "rm " + TEST_APP_LOCATION + apk.getName();
+            getDevice().executeShellCommand(command);
+            getDevice().uninstallPackage(TEST_APP_PKG);
+            getDevice().uninstallPackage(PACKAGE_INSTALLER_APK);
+            if (unknownSourceSetting != null) {
+                putSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, unknownSourceSetting,
+                        mUserId);
+            }
+        }
+    }
+
     protected void executeDeviceTestClass(String className) throws Exception {
         assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId));
     }
@@ -213,4 +267,18 @@
     protected void executeDeviceTestMethod(String className, String testName) throws Exception {
         assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, testName, mUserId));
     }
+
+    private void changeUserRestrictionForUser(String key, String command, int userId)
+            throws DeviceNotAvailableException {
+        String adbCommand = "am start -W --user " + userId
+                + " -c android.intent.category.DEFAULT "
+                + " --es extra-command " + command
+                + " --es extra-restriction-key " + key
+                + " " + DEVICE_ADMIN_PKG + "/.UserRestrictionActivity";
+        String commandOutput = getDevice().executeShellCommand(adbCommand);
+        CLog.logAndDisplay(LogLevel.INFO,
+                "Output for command " + adbCommand + ": " + commandOutput);
+        assertTrue("Command was expected to succeed " + commandOutput,
+                commandOutput.contains("Status: ok"));
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 4f267d1..96ca469 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -16,12 +16,6 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.io.File;
-
 /**
  * Set of tests for Device Owner use cases.
  */
@@ -35,10 +29,6 @@
     private static final String MANAGED_PROFILE_ADMIN =
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
 
-    private static final String TEST_APP_APK = "CtsSimpleApp.apk";
-    private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
-    private static final String TEST_APP_LOCATION = "/data/local/tmp/";
-
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
     private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
@@ -93,19 +83,6 @@
         }
     }
 
-    public void testPackageInstall() throws Exception {
-        final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
-        try {
-            getDevice().uninstallPackage(TEST_APP_PKG);
-            assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
-            executeDeviceOwnerTest("PackageInstallTest");
-        } finally {
-            String command = "rm " + TEST_APP_LOCATION + apk.getName();
-            String commandOutput = getDevice().executeShellCommand(command);
-            getDevice().uninstallPackage(TEST_APP_PKG);
-        }
-    }
-
     public void testSystemUpdatePolicy() throws Exception {
         executeDeviceOwnerTest("SystemUpdatePolicyTest");
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
index 8da189f..1d5dd11 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
@@ -25,11 +25,13 @@
  * apps.
  */
 public class LauncherAppsMultiUserTest extends BaseLauncherAppsTest {
+    private static final String FEATURE_LIVE_TV = "android.software.live_tv";
 
     private int mSecondaryUserId;
     private int mSecondaryUserSerialNumber;
 
     private boolean mMultiUserSupported;
+    private boolean mHasLiveTvFeature;
 
     @Override
     protected void setUp() throws Exception {
@@ -37,6 +39,7 @@
         // We need multi user to be supported in order to create a secondary user
         // and api level 21 to support LauncherApps
         mMultiUserSupported = getMaxNumberOfUsersSupported() > 1 && getDevice().getApiLevel() >= 21;
+        mHasLiveTvFeature = hasDeviceFeature(FEATURE_LIVE_TV);
 
         if (mMultiUserSupported) {
             removeTestUsers();
@@ -58,7 +61,7 @@
     }
 
     public void testGetActivitiesForNonProfileFails() throws Exception {
-        if (!mMultiUserSupported) {
+        if (!mMultiUserSupported || mHasLiveTvFeature) {
             return;
         }
         installApp(SIMPLE_APP_APK);
@@ -73,7 +76,7 @@
     }
 
     public void testNoLauncherCallbackPackageAddedSecondaryUser() throws Exception {
-        if (!mMultiUserSupported) {
+        if (!mMultiUserSupported || mHasLiveTvFeature) {
             return;
         }
         startCallbackService();
diff --git a/tests/tests/netlegacy22/Android.mk b/hostsidetests/dumpsys/FramestatsTestApp/Android.mk
similarity index 66%
rename from tests/tests/netlegacy22/Android.mk
rename to hostsidetests/dumpsys/FramestatsTestApp/Android.mk
index 3174652..1104523 100644
--- a/tests/tests/netlegacy22/Android.mk
+++ b/hostsidetests/dumpsys/FramestatsTestApp/Android.mk
@@ -12,5 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Build the API tests and the permissions tests using their own makefiles.
-include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_PACKAGE_NAME := CtsFramestatsTestApp
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/dumpsys/FramestatsTestApp/AndroidManifest.xml b/hostsidetests/dumpsys/FramestatsTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..3a9f902
--- /dev/null
+++ b/hostsidetests/dumpsys/FramestatsTestApp/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.cts.framestatstestapp">
+    <!--
+    A simple app that draws at least one frame. Used by framestats
+    test.
+    -->
+    <application>
+        <activity android:name=".FramestatsTestAppActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/DisableContextActivity.java b/hostsidetests/dumpsys/FramestatsTestApp/src/com/android/cts/framestatstestapp/FramestatsTestAppActivity.java
similarity index 64%
rename from tests/tests/assist/testapp/src/android/voiceinteraction/testapp/DisableContextActivity.java
rename to hostsidetests/dumpsys/FramestatsTestApp/src/com/android/cts/framestatstestapp/FramestatsTestAppActivity.java
index ae570d8..7370508 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/DisableContextActivity.java
+++ b/hostsidetests/dumpsys/FramestatsTestApp/src/com/android/cts/framestatstestapp/FramestatsTestAppActivity.java
@@ -13,26 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.assist.testapp;
+package com.android.cts.framestatstestapp;
 
 import android.app.Activity;
-import android.content.Intent;
 import android.os.Bundle;
-import android.util.Log;
+import android.os.Trace;
+import android.view.View;
 
-public class DisableContextActivity extends Activity {
-    static final String TAG = "TestApp";
-
+public class FramestatsTestAppActivity extends Activity {
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Log.i(TAG, "TestApp created");
-        setContentView(R.layout.test_app);
+        View v = new View(this);
+        v.setBackgroundColor(0xFF00FF00);
+        setContentView(v);
     }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-    }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index a787cdd..0daae03 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -16,11 +16,15 @@
 
 package android.dumpsys.cts;
 
-import com.android.ddmlib.Log;
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
 
 import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
 import java.io.StringReader;
 import java.util.HashSet;
 import java.util.Set;
@@ -28,8 +32,10 @@
 /**
  * Test to check the format of the dumps of various services (currently only procstats is tested).
  */
-public class DumpsysHostTest extends DeviceTestCase {
+public class DumpsysHostTest extends DeviceTestCase implements IBuildReceiver {
     private static final String TAG = "DumpsysHostTest";
+    private static final String TEST_APK = "CtsFramestatsTestApp.apk";
+    private static final String TEST_PKG = "com.android.cts.framestatstestapp";
 
     /**
      * A reference to the device under test.
@@ -815,17 +821,38 @@
      */
     public void testGfxinfoFramestats() throws Exception {
         final String MARKER = "---PROFILEDATA---";
-        final int TIMESTAMP_COUNT = 14;
 
-        String frameinfo = mDevice.executeShellCommand("dumpsys gfxinfo com.android.systemui framestats");
-        assertNotNull(frameinfo);
-        assertTrue(frameinfo.length() > 0);
-        int profileStart = frameinfo.indexOf(MARKER);
-        int profileEnd = frameinfo.indexOf(MARKER, profileStart + 1);
-        assertTrue(profileStart >= 0);
-        assertTrue(profileEnd > profileStart);
-        String profileData = frameinfo.substring(profileStart + MARKER.length(), profileEnd);
-        assertTrue(profileData.length() > 0);
+        try {
+            // cleanup test apps that might be installed from previous partial test run
+            getDevice().uninstallPackage(TEST_PKG);
+
+            // install the test app
+            File testAppFile = mCtsBuild.getTestApp(TEST_APK);
+            String installResult = getDevice().installPackage(testAppFile, false);
+            assertNull(
+                    String.format("failed to install atrace test app. Reason: %s", installResult),
+                    installResult);
+
+            getDevice().executeShellCommand("am start -W " + TEST_PKG);
+
+            String frameinfo = mDevice.executeShellCommand("dumpsys gfxinfo " +
+                    TEST_PKG + " framestats");
+            assertNotNull(frameinfo);
+            assertTrue(frameinfo.length() > 0);
+            int profileStart = frameinfo.indexOf(MARKER);
+            int profileEnd = frameinfo.indexOf(MARKER, profileStart + 1);
+            assertTrue(profileStart >= 0);
+            assertTrue(profileEnd > profileStart);
+            String profileData = frameinfo.substring(profileStart + MARKER.length(), profileEnd);
+            assertTrue(profileData.length() > 0);
+            validateProfileData(profileData);
+        } finally {
+            getDevice().uninstallPackage(TEST_PKG);
+        }
+    }
+
+    private void validateProfileData(String profileData) throws IOException {
+        final int TIMESTAMP_COUNT = 14;
         boolean foundAtLeastOneRow = false;
         try (BufferedReader reader = new BufferedReader(
                 new StringReader(profileData))) {
@@ -872,6 +899,16 @@
         assertTrue(foundAtLeastOneRow);
     }
 
+    private CtsBuildHelper mCtsBuild;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+    }
+
     private static long assertInteger(String input) {
         try {
             return Long.parseLong(input);
diff --git a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
index a0d3167..abb1ac4 100644
--- a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
@@ -589,9 +589,9 @@
         assertDomainN("u:r:zygote:s0", "zygote", "zygote64");
     }
 
-    /* drm server is always present */
+    /* Checks drmserver for devices that require it */
     public void testDrmServerDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:drmserver:s0", "/system/bin/drmserver");
+        assertDomainZeroOrOne("u:r:drmserver:s0", "/system/bin/drmserver");
     }
 
     /* Media server is always running */
diff --git a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
old mode 100644
new mode 100755
index 63c7472..0e11111
--- a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
+++ b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
@@ -77,27 +77,42 @@
      * @param threshold maximum difference per channel
      * @return {@code true} if the images are similar, false otherwise
      */
-    private static boolean compare(BufferedImage expected, BufferedImage actual,
-            int threshold) {
-        final int w = actual.getWidth();
-        final int h = actual.getHeight();
-        if (w != expected.getWidth() || h != expected.getHeight()) {
+    private static int getAlphaScaledBlue(final int color) {
+        return (color & 0x000000FF) * getAlpha(color) / 255;
+    }
+
+    private static int getAlphaScaledGreen(final int color) {
+        return ((color & 0x0000FF00) >> 8) * getAlpha(color) / 255;
+    }
+
+    private static int getAlphaScaledRed(final int color) {
+        return ((color & 0x00FF0000) >> 16) * getAlpha(color) / 255;
+    }
+
+    private static int getAlpha(final int color) {
+        // use logical shift for keeping an unsigned value
+        return (color & 0xFF000000) >>> 24;
+    }
+
+    private static boolean compare(BufferedImage reference, BufferedImage generated, int threshold) {
+        final int w = generated.getWidth();
+        final int h = generated.getHeight();
+        if (w != reference.getWidth() || h != reference.getHeight()) {
             return false;
         }
 
         for (int i = 0; i < w; i++) {
             for (int j = 0; j < h; j++) {
-                final int p1 = expected.getRGB(i, j);
-                final int p2 = actual.getRGB(i, j);
-                final int dr = (p1 & 0x000000FF) - (p2 & 0x000000FF);
-                final int dg = ((p1 & 0x0000FF00) - (p2 & 0x0000FF00)) >> 8;
-                final int db = ((p1 & 0x00FF0000) - (p2 & 0x00FF0000)) >> 16;
-                final int da = ((p1 & 0xFF000000) - (p2 & 0xFF000000)) >> 24;
+                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 ||
-                        Math.abs(da) > threshold) {
+                        Math.abs(dr) > threshold) {
                     return false;
                 }
             }
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index 7e2bfe3..b3ebbad 100755
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -330,13 +330,34 @@
                 ex.release();
             }
         }
-        return false;
+        return true;
     }
 
     public static boolean checkCodecsForPath(Context context, String path) {
         return check(hasCodecsForPath(context, path), "no decoder found");
     }
 
+    public static boolean hasCodecForDomain(boolean encoder, String domain) {
+        for (MediaCodecInfo info : sMCL.getCodecInfos()) {
+            if (encoder != info.isEncoder()) {
+                continue;
+            }
+
+            for (String type : info.getSupportedTypes()) {
+                if (type.toLowerCase().startsWith(domain.toLowerCase() + "/")) {
+                    Log.i(TAG, "found codec " + info.getName() + " for mime " + type);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean checkCodecForDomain(boolean encoder, String domain) {
+        return check(hasCodecForDomain(encoder, domain),
+                "no " + domain + (encoder ? " encoder" : " decoder") + " found");
+    }
+
     private static boolean hasCodecForMime(boolean encoder, String mime) {
         for (MediaCodecInfo info : sMCL.getCodecInfos()) {
             if (encoder != info.isEncoder()) {
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp
index b8e2acf..16504fd 100644
--- a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp
@@ -22,6 +22,14 @@
 
 // Used to center the grid on the screen.
 #define CENTER_GRID(x) ((((x) * 2.0 + 1) - OFFSCREEN_GRID_SIZE) / OFFSCREEN_GRID_SIZE)
+// Leave a good error message if something fails.
+#define EGL_RESULT_CHECK(X) do { \
+                                   EGLint error = eglGetError(); \
+                                   if (!(X) || error != EGL_SUCCESS) { \
+                                       ALOGE("EGL error '%d' at %s:%d", error, __FILE__, __LINE__);\
+                                       return false; \
+                                    } \
+                            } while (0)
 
 static const int FBO_NUM_VERTICES = 6;
 
@@ -66,7 +74,7 @@
         EGL_NONE };
 
 static const EGLint configAttribs[] = {
-        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
         EGL_RED_SIZE, 8,
         EGL_GREEN_SIZE, 8,
@@ -78,53 +86,60 @@
 
 static const int FBO_SIZE = 128;
 
-Renderer::Renderer(ANativeWindow* window, bool offscreen, int workload) :
-        mOffscreen(offscreen), mWindow(window), mEglDisplay(EGL_NO_DISPLAY),
-        mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT), mWorkload(workload) {
+Renderer::Renderer(EGLNativeWindowType window, bool offscreen) :
+        mOffscreen(offscreen), mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE),
+        mEglContext(EGL_NO_CONTEXT), mWindow(window)  {
 }
 
-bool Renderer::setUp() {
+bool Renderer::eglSetUp() {
     SCOPED_TRACE();
     mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (EGL_NO_DISPLAY == mEglDisplay || EGL_SUCCESS != eglGetError()) {
-        return false;
-    }
+    EGL_RESULT_CHECK(mEglDisplay != EGL_NO_DISPLAY);
 
     EGLint major;
     EGLint minor;
-    if (!eglInitialize(mEglDisplay, &major, &minor) || EGL_SUCCESS != eglGetError()) {
-        return false;
-    }
+    EGL_RESULT_CHECK(eglInitialize(mEglDisplay, &major, &minor));
 
     EGLint numConfigs = 0;
-    if (!eglChooseConfig(mEglDisplay, configAttribs, &mGlConfig, 1, &numConfigs)
-            || EGL_SUCCESS != eglGetError()) {
-        return false;
-    }
+    EGL_RESULT_CHECK(eglChooseConfig(mEglDisplay, configAttribs, &mGlConfig, 1, &numConfigs)
+                     && (numConfigs > 0));
 
     mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mWindow, NULL);
-    if (EGL_NO_SURFACE == mEglSurface || EGL_SUCCESS != eglGetError()) {
-        return false;
-    }
+    EGL_RESULT_CHECK(mEglSurface != EGL_NO_SURFACE);
 
     mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, contextAttribs);
-    if (EGL_NO_CONTEXT == mEglContext || EGL_SUCCESS != eglGetError()) {
-        return false;
+    EGL_RESULT_CHECK(mEglContext != EGL_NO_CONTEXT);
+
+    EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
+    EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &mWidth));
+    EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &mHeight));
+
+    return true;
+}
+
+void Renderer::eglTearDown() {
+    SCOPED_TRACE();
+    eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+    if (mEglContext != EGL_NO_CONTEXT) {
+        eglDestroyContext(mEglDisplay, mEglContext);
+        mEglContext = EGL_NO_CONTEXT;
     }
 
-    if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
-            || EGL_SUCCESS != eglGetError()) {
-        return false;
+    if (mEglSurface != EGL_NO_SURFACE) {
+        mEglSurface = EGL_NO_SURFACE;
     }
 
-    if (!eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &mWidth)
-            || EGL_SUCCESS != eglGetError()) {
-        return false;
+    if (mEglDisplay != EGL_NO_DISPLAY) {
+        eglTerminate(mEglDisplay);
+        mEglDisplay = EGL_NO_DISPLAY;
     }
-    if (!eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &mHeight)
-            || EGL_SUCCESS != eglGetError()) {
-        return false;
-    }
+}
+
+bool Renderer::setUp(int /*workload*/) {
+    SCOPED_TRACE();
+
+    EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
 
     if (mOffscreen) {
         mFboWidth = FBO_SIZE;
@@ -178,6 +193,7 @@
         ALOGE("GLError %d in setUp", err);
         return false;
     }
+
     return true;
 }
 
@@ -202,29 +218,14 @@
         ALOGE("GLError %d in tearDown", err);
         return false;
     }
-    if (mEglContext != EGL_NO_CONTEXT) {
-        eglDestroyContext(mEglDisplay, mEglContext);
-        mEglContext = EGL_NO_CONTEXT;
-    }
-    if (mEglSurface != EGL_NO_SURFACE) {
-        eglDestroySurface(mEglDisplay, mEglSurface);
-        mEglSurface = EGL_NO_SURFACE;
-    }
-    if (mEglDisplay != EGL_NO_DISPLAY) {
-        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-        eglTerminate(mEglDisplay);
-        mEglDisplay = EGL_NO_DISPLAY;
-    }
 
-    return EGL_SUCCESS == eglGetError();
+    return true;
 }
 
 bool Renderer::draw() {
     SCOPED_TRACE();
-    if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
-            || EGL_SUCCESS != eglGetError()) {
-        return false;
-    }
+
+    EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
 
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
     glViewport(0, 0, mWidth, mHeight);
@@ -287,5 +288,6 @@
         return false;
     }
 
-    return eglSwapBuffers(mEglDisplay, mEglSurface);
+    EGL_RESULT_CHECK(eglSwapBuffers(mEglDisplay, mEglSurface)); 
+    return true;
 }
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h
index caa1634..3c62a26 100644
--- a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h
+++ b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h
@@ -14,17 +14,18 @@
 #ifndef RENDERER_H
 #define RENDERER_H
 
-#include <android/native_window.h>
-
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
 class Renderer {
 public:
-    Renderer(ANativeWindow* window, bool offscreen, int workload);
-    virtual bool setUp();
+    Renderer(EGLNativeWindowType window, bool offscreen);
+    virtual bool setUp(int workload);
     virtual bool tearDown();
+    bool eglSetUp();
+    void eglTearDown();
+
     bool draw();
     virtual void drawWorkload() = 0;
     virtual ~Renderer() {};
@@ -32,7 +33,6 @@
     static const int OFFSCREEN_GRID_SIZE = 10;
     bool mOffscreen;
 protected:
-    ANativeWindow* mWindow;
     EGLDisplay mEglDisplay;
     EGLSurface mEglSurface;
     EGLContext mEglContext;
@@ -40,7 +40,6 @@
     GLuint mProgramId;
     EGLint mWidth;
     EGLint mHeight;
-    int mWorkload;
     int mFboWidth;// Frame buffer width
     int mFboHeight;// Frame buffer height
     GLuint mFboId;// Frame buffer id
@@ -52,5 +51,7 @@
     GLuint mFboYOffsetUniformHandle;// Frame buffer y offset uniform handle
     GLuint mFboPositionHandle;// Frame buffer position handle
     GLuint mFboTexCoordHandle;// Frame buffer texture coordinate handle
+private:
+    EGLNativeWindowType mWindow;
 };
 #endif
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp b/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
index 9d39af9..856da1e 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
@@ -28,16 +28,24 @@
 
 // Holds the current benchmark's renderer.
 Renderer* gRenderer = NULL;
+ANativeWindow* gNativeWindow = NULL;
+
+enum {
+    FULL_PIPELINE_BENCHMARK = 0,
+    PIXEL_OUTPUT_BENCHMARK = 1,
+    SHADER_PERF_BENCHMARK = 2,
+    CONTEXT_SWITCH_BENCHMARK = 3
+};
 
 extern "C" JNIEXPORT jboolean JNICALL
 Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_startBenchmark(
-        JNIEnv* env, jclass clazz, jint numFrames, jdoubleArray frameTimes) {
+        JNIEnv* env, jclass /*clazz*/, jint workload, jint numFrames, jdoubleArray frameTimes) {
     if (gRenderer == NULL) {
         return false;
     }
 
     // Sets up the renderer.
-    bool success = gRenderer->setUp();
+    bool success = gRenderer->setUp(workload);
 
     // Records the start time.
     double start = GLUtils::currentTimeMillis();
@@ -60,41 +68,56 @@
     double times[] = {start, end};
     env->SetDoubleArrayRegion(frameTimes, 0, 2, times);
 
-    // Tears down and deletes the renderer.
     success = gRenderer->tearDown() && success;
-    delete gRenderer;
-    gRenderer = NULL;
     return success;
 }
 
 // The following functions create the renderers for the various benchmarks.
 extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupFullPipelineBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
-    gRenderer = new FullPipelineRenderer(
-            ANativeWindow_fromSurface(env, surface), offscreen, workload);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupPixelOutputBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
-    gRenderer = new PixelOutputRenderer(
-            ANativeWindow_fromSurface(env, surface), offscreen, workload);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupShaderPerfBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
-    gRenderer = new ShaderPerfRenderer(
-            ANativeWindow_fromSurface(env, surface), offscreen, workload);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupContextSwitchBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
-    if (workload <= 8) {
-        // This test uses 8 iterations, so workload can't be more than 8.
-        gRenderer = new ContextSwitchRenderer(
-                ANativeWindow_fromSurface(env, surface), offscreen, workload);
+Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupBenchmark(
+        JNIEnv* env, jclass /*clazz*/, jobject surface, jint benchmark,
+        jboolean offscreen) {
+    gNativeWindow = ANativeWindow_fromSurface(env, surface);
+    switch (benchmark) {
+        case FULL_PIPELINE_BENCHMARK:
+            gRenderer = new FullPipelineRenderer(gNativeWindow, offscreen);
+            break;
+        case PIXEL_OUTPUT_BENCHMARK:
+            gRenderer = new PixelOutputRenderer(gNativeWindow, offscreen);
+            break;
+        case SHADER_PERF_BENCHMARK:
+            gRenderer = new ShaderPerfRenderer(gNativeWindow, offscreen);
+            break;
+        case CONTEXT_SWITCH_BENCHMARK:
+            gRenderer = new ContextSwitchRenderer(gNativeWindow, offscreen);
+            break;
+        default:
+            ALOGE("Unknown benchmark '%d'", benchmark);
+            ANativeWindow_release(gNativeWindow);
+            gNativeWindow = NULL;
+            return;
     }
+
+    // Set up call will log error conditions
+    if (!gRenderer->eglSetUp()) {
+        delete gRenderer;
+        gRenderer = NULL;
+
+        ANativeWindow_release(gNativeWindow);
+        gNativeWindow = NULL;
+    }
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_tearDownBenchmark(
+        JNIEnv* /*env*/, jclass /*clazz*/) {
+    if (gRenderer == NULL) {
+        return;
+    }
+    gRenderer->eglTearDown();
+    delete gRenderer;
+    gRenderer = NULL;
+
+    ANativeWindow_release(gNativeWindow);
+    gNativeWindow = NULL;
 }
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
index 7fd4093..1127d88 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
@@ -74,13 +74,14 @@
         "  gl_FragColor = texture2D(u_Texture, v_TexCoord);"
         "}";
 
-ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, bool offscreen, int workload) :
-        Renderer(window, offscreen, workload), mContexts(NULL) {
+ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, bool offscreen) :
+        Renderer(window, offscreen), mContexts(NULL), mWorkload(0) {
 }
 
-bool ContextSwitchRenderer::setUp() {
+bool ContextSwitchRenderer::setUp(int workload) {
     SCOPED_TRACE();
-    if (!Renderer::setUp()) {
+    mWorkload = workload;
+    if (!Renderer::setUp(workload)) {
         return false;
     }
 
@@ -137,7 +138,7 @@
 bool ContextSwitchRenderer::tearDown() {
     SCOPED_TRACE();
     if (mContexts) {
-        // Destroy the contexts, the main one will be handled by Renderer::tearDown().
+        // Destroy the contexts, the main one will be handled by Renderer::eglTearDown().
         for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) {
             if (mOffscreen) {
                 if (mFboIds[i] != 0) {
@@ -146,6 +147,7 @@
                     mFboIds[i] = 0;
                 }
             }
+            eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
             eglDestroyContext(mEglDisplay, mContexts[i]);
         }
         delete[] mContexts;
@@ -163,6 +165,11 @@
 
 void ContextSwitchRenderer::drawWorkload() {
     SCOPED_TRACE();
+
+    if (mWorkload > 8) {
+        return; // This test does not support higher workloads.
+    }
+
     // Set the background clear color to black.
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
@@ -216,6 +223,7 @@
         }
     }
 
+    eglWaitSyncKHR(mEglDisplay, fence, 0);
     eglDestroySyncKHR(mEglDisplay, fence);
 
     // Switch back to the main context.
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h
index 51a4376..ae320ff 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h
@@ -18,9 +18,9 @@
 
 class ContextSwitchRenderer: public Renderer {
 public:
-    ContextSwitchRenderer(ANativeWindow* window, bool offscreen, int workload);
+    ContextSwitchRenderer(ANativeWindow* window, bool offscreen);
     virtual ~ContextSwitchRenderer() {};
-    bool setUp();
+    bool setUp(int workload);
     bool tearDown();
     void drawWorkload();
 private:
@@ -31,6 +31,7 @@
     GLuint mTranslateUniformHandle;
     GLuint mPositionHandle;
     GLuint mTexCoordHandle;
+    int mWorkload;
 };
 
 #endif
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
index 97462b5..0f75f81 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
@@ -91,15 +91,15 @@
         "  gl_FragColor = (diffuse * texture2D(u_Texture, v_TexCoordinate));\n"
         "}";
 
-FullPipelineRenderer::FullPipelineRenderer(ANativeWindow* window, bool offscreen, int workload) :
-        Renderer(window, offscreen, workload), mProgram(NULL), mSceneGraph(NULL),
+FullPipelineRenderer::FullPipelineRenderer(ANativeWindow* window, bool offscreen) :
+        Renderer(window, offscreen), mProgram(NULL), mSceneGraph(NULL),
         mModelMatrix(NULL), mViewMatrix(NULL), mProjectionMatrix(NULL), mMesh(NULL),
         mTextureId(0) {
 }
 
-bool FullPipelineRenderer::setUp() {
+bool FullPipelineRenderer::setUp(int workload) {
     SCOPED_TRACE();
-    if (!Renderer::setUp()) {
+    if (!Renderer::setUp(workload)) {
         return false;
     }
 
@@ -147,7 +147,7 @@
         return false;
     }
 
-    float count = mWorkload * mWorkload;
+    float count = workload * workload;
     float middle = count / 2.0f;
     float scale = 2.0f / count;
 
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h
index 84616b4..ce44760 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h
@@ -22,9 +22,9 @@
 
 class FullPipelineRenderer: public Renderer {
 public:
-    FullPipelineRenderer(ANativeWindow* window, bool offscreen, int workload);
+    FullPipelineRenderer(ANativeWindow* window, bool offscreen);
     virtual ~FullPipelineRenderer() {};
-    bool setUp();
+    bool setUp(int workload);
     bool tearDown();
     void drawWorkload();
 private:
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
index 287ebfb..3a3b9d1 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
@@ -50,13 +50,14 @@
         "  gl_FragColor = texture2D(u_Texture, v_TexCoord);"
         "}";
 
-PixelOutputRenderer::PixelOutputRenderer(ANativeWindow* window, bool offscreen, int workload) :
-        Renderer(window, offscreen, workload) {
+PixelOutputRenderer::PixelOutputRenderer(ANativeWindow* window, bool offscreen) :
+        Renderer(window, offscreen), mWorkload(0) {
 }
 
-bool PixelOutputRenderer::setUp() {
+bool PixelOutputRenderer::setUp(int workload) {
     SCOPED_TRACE();
-    if (!Renderer::setUp()) {
+    mWorkload = workload;
+    if (!Renderer::setUp(workload)) {
         return false;
     }
 
@@ -80,6 +81,11 @@
 
 bool PixelOutputRenderer::tearDown() {
     SCOPED_TRACE();
+    if (mProgramId != 0)
+    {
+        glDeleteProgram(mProgramId);
+        mProgramId = 0;
+    }
     if (mTextureId != 0) {
         glDeleteTextures(1, &mTextureId);
         mTextureId = 0;
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h
index e6b5692..816da6a 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h
@@ -18,9 +18,9 @@
 
 class PixelOutputRenderer: public Renderer {
 public:
-    PixelOutputRenderer(ANativeWindow* window, bool offscreen, int workload);
+    PixelOutputRenderer(ANativeWindow* window, bool offscreen);
     virtual ~PixelOutputRenderer() {};
-    bool setUp();
+    bool setUp(int workload);
     bool tearDown();
     void drawWorkload();
 private:
@@ -28,6 +28,7 @@
     GLuint mTextureUniformHandle;
     GLuint mPositionHandle;
     GLuint mTexCoordHandle;
+    int mWorkload;
 };
 
 #endif
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
index 1cbc839..a02f4fe 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
@@ -91,13 +91,13 @@
     return destAddr - destStart;
 }
 
-ShaderPerfRenderer::ShaderPerfRenderer(ANativeWindow* window, bool offscreen, int workload) :
-        Renderer(window, offscreen, workload) {
+ShaderPerfRenderer::ShaderPerfRenderer(ANativeWindow* window, bool offscreen) :
+        Renderer(window, offscreen) {
 }
 
-bool ShaderPerfRenderer::setUp() {
+bool ShaderPerfRenderer::setUp(int workload) {
     SCOPED_TRACE();
-    if (!Renderer::setUp()) {
+    if (!Renderer::setUp(workload)) {
         return false;
     }
 
@@ -106,7 +106,7 @@
     // Add the first part.
     int index = charCopy(SP_FRAGMENT_1, spFragment, 0);
     // Add the count, overwriting the '\0' added by charCopy.
-    spFragment[index - 1] = (char) (((int) '0') + mWorkload);
+    spFragment[index - 1] = (char) (((int) '0') + workload);
     // Add the second part.
     index += charCopy(SP_FRAGMENT_2, spFragment, index);
     // Create program.
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h
index 52fac43..c804202 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h
@@ -18,9 +18,9 @@
 
 class ShaderPerfRenderer: public Renderer {
 public:
-    ShaderPerfRenderer(ANativeWindow* window, bool offscreen, int workload);
+    ShaderPerfRenderer(ANativeWindow* window, bool offscreen);
     virtual ~ShaderPerfRenderer() {};
-    bool setUp();
+    bool setUp(int workload);
     void drawWorkload();
 private:
     GLuint mTextureId;
diff --git a/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp b/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
index 1857848..dc0b4e2 100644
--- a/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
+++ b/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
@@ -23,7 +23,7 @@
 
 extern "C" JNIEXPORT jboolean JNICALL
 Java_com_android_cts_opengl_reference_GLGameActivity_startBenchmark(
-        JNIEnv* env, jclass clazz, jobject assetManager, jobject surface, jint numFrames,
+    JNIEnv* env, jclass /*clazz*/, jobject assetManager, jobject surface, jint numFrames,
         jdoubleArray setUpTimes, jdoubleArray updateTimes, jdoubleArray renderTimes) {
 
     GLUtils::setEnvAndAssetManager(env, assetManager);
@@ -32,9 +32,10 @@
         return false;
     }
 
-    ReferenceRenderer* renderer = new ReferenceRenderer(ANativeWindow_fromSurface(env, surface));
-
-    bool success = renderer->setUp();
+    ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
+    ReferenceRenderer* renderer = new ReferenceRenderer(nativeWindow);
+    bool success = renderer->eglSetUp();
+    success = renderer->setUp(0) && success;
     env->SetDoubleArrayRegion(
             setUpTimes, 0, ReferenceRenderer::NUM_SETUP_TIMES, renderer->mSetUpTimes);
 
@@ -54,7 +55,11 @@
     env->SetDoubleArrayRegion(renderTimes, 0, numFrames, renders);
 
     success = renderer->tearDown() && success;
+    renderer->eglTearDown();
     delete renderer;
     renderer = NULL;
+
+    ANativeWindow_release(nativeWindow);
+
     return success;
 }
diff --git a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp
index 8f7703e..3b12ee1 100644
--- a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp
@@ -22,10 +22,10 @@
 #include <Trace.h>
 
 ReferenceRenderer::ReferenceRenderer(ANativeWindow* window) :
-        Renderer(window, false, 0) {
+        Renderer(window, false) {
 }
 
-bool ReferenceRenderer::setUp() {
+bool ReferenceRenderer::setUp(int workload) {
     SCOPED_TRACE();
     // Reset the times.
     for (int i = 0; i < NUM_SETUP_TIMES; i++) {
@@ -33,7 +33,7 @@
     }
     // Set up OpenGLES.
     double start = GLUtils::currentTimeMillis();
-    if (!Renderer::setUp()) {
+    if (!Renderer::setUp(workload)) {
         return false;
     }
     mSetUpTimes[0] = GLUtils::currentTimeMillis() - start;
diff --git a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h
index d10297a..f5c4b65 100644
--- a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h
@@ -23,7 +23,7 @@
 public:
     ReferenceRenderer(ANativeWindow* window);
     virtual ~ReferenceRenderer() {};
-    bool setUp();
+    bool setUp(int workload);
     bool tearDown();
     bool update(int frame);
     void drawWorkload();
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
index 5dc9b88..6defdb7 100644
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
+++ b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
@@ -102,19 +102,12 @@
         }
     }
 
-    private static native void setupFullPipelineBenchmark(
-            Surface surface, boolean offscreen, int workload);
+    private static native boolean setupBenchmark(
+            Surface surface, int benchmark, boolean offscreen);
 
-    private static native void setupPixelOutputBenchmark(
-            Surface surface, boolean offscreen, int workload);
+    private static native boolean startBenchmark(int workload, int numFrames, double[] frameTimes);
 
-    private static native void setupShaderPerfBenchmark(
-            Surface surface, boolean offscreen, int workload);
-
-    private static native void setupContextSwitchBenchmark(
-            Surface surface, boolean offscreen, int workload);
-
-    private static native boolean startBenchmark(int numFrames, double[] frameTimes);
+    private static native void tearDownBenchmark();
 
     /**
      * This thread runs the benchmarks, freeing the UI thread.
@@ -138,36 +131,29 @@
             watchDog = new WatchDog(mTimeout, this);
             // Used to record the start and end time of the iteration.
             double[] times = new double[2];
-            for (int i = 0; i < mNumIterations && success; i++) {
-                // The workload to use for this iteration.
-                int workload = i + 1;
+            try {
                 // Setup the benchmark.
-                switch (mBenchmark) {
-                    case FullPipeline:
-                        setupFullPipelineBenchmark(mSurface, mOffscreen, workload);
-                        break;
-                    case PixelOutput:
-                        setupPixelOutputBenchmark(mSurface, mOffscreen, workload);
-                        break;
-                    case ShaderPerf:
-                        setupShaderPerfBenchmark(mSurface, mOffscreen, workload);
-                        break;
-                    case ContextSwitch:
-                        setupContextSwitchBenchmark(mSurface, mOffscreen, workload);
-                        break;
-                }
-                watchDog.start();
-                // Start benchmark.
-                success = startBenchmark(mNumFrames, times);
-                watchDog.stop();
-
-                if (!success) {
-                    setException(new Exception("Benchmark failed to run"));
-                } else {
-                    // Calculate FPS.
-                    mFpsValues[i] = mNumFrames * 1000.0f / (times[1] - times[0]);
+                setupBenchmark(mSurface, mBenchmark.ordinal(), mOffscreen);
+                for (int i = 0; i < mNumIterations && success; i++) {
+                    // The workload to use for this iteration.
+                    int workload = i + 1;
+                    watchDog.start();
+                    // Start benchmark.
+                    success = startBenchmark(workload, mNumFrames, times);
+                    watchDog.stop();
+                    if (!success) {
+                        setException(new Exception("Benchmark failed to run"));
+                    } else {
+                        // Calculate FPS.
+                        mFpsValues[i] = mNumFrames * 1000.0f / (times[1] - times[0]);
+                    }
                 }
             }
+            finally
+            {
+                tearDownBenchmark();
+            }
+
             complete();
             Log.i(TAG, mBenchmark + " Benchmark Completed");
         }
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 29c5035..2cb99c4 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -158,6 +158,14 @@
   bug: 17508787
 },
 {
+  description: "This test should be outside of official CTS suite until it is verified for all Nexus devices",
+  names: [
+    "com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions",
+    "com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions"
+  ],
+  bug: 18928535
+},
+{
   description: "Test is not yet properly implemented",
   names: [
     "android.voicesettings.cts.ZenModeTest#testAll"
@@ -254,6 +262,13 @@
   bug: 23008511
 },
 {
+  description: "Light status bar CTS coming in late",
+  names: [
+    "com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons"
+  ],
+  bug: 23427621
+},
+{
   description: "known failures",
   names: [
     "android.hardware.cts.SensorBatchingTests#testAccelerometer_50hz_batching",
@@ -287,5 +302,63 @@
     "com.android.cts.app.os.OsHostTests#testNonExportedActivities"
   ],
   bug: 23779168
+},
+{
+  description: "New assist tests that do not yet have a track record.",
+  names: [
+    "android.assist.cts.AssistantContentViewTest",
+    "android.assist.cts.ExtraAssistDataTest",
+    "android.assist.cts.FocusChangeTest",
+    "android.assist.cts.LargeViewHierarchyTest",
+    "android.assist.cts.ScreenshotTest",
+    "android.assist.cts.TextViewTest",
+    "android.assist.cts.WebViewTest"
+  ],
+  bug: 21668302
+},
+{
+  description: "ConnectivityConstraintTest job scheduler not working.",
+  names: [
+     "android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withWifi",
+     "android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintExecutes_withWifi"
+  ],
+  bug: 21262226
+},
+{
+   description: "ConnectivityConstraintTest times out.",
+   names: [
+     "android.jobscheduler.cts.TimingConstraintsTest#testJobParameters_unexpiredDeadline"
+   ],
+   bug: 23144425
+},
+{
+   description: "Telephony returning wrong value.",
+   names: [
+     "android.telephony.cts.CellInfoTest#testCellInfo"
+   ],
+   bug: 23979591
+},
+{
+   description: "Video encoding tests are timing out.",
+   names: [
+     "android.media.cts.VideoEncoderTest#testGoogH264FlexArbitraryW",
+     "android.media.cts.VideoEncoderTest#testGoogH264SurfArbitraryW"
+   ],
+   bug: 23827982
+},
+{
+  description: "tests not yet ready",
+  names: [
+    "android.telecom.cts.OutgoingCallTest#testStartCallWithSpeakerphoneFalse_SpeakerphoneOffInCall",
+    "android.telecom.cts.OutgoingCallTest#testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault"
+  ],
+  bug: 24067587
+},
+{
+  description: "protected broadcast not working",
+  names: [
+   "android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts"
+  ],
+  bug: 23192492
 }
 ]
diff --git a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java b/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
index a86a707..241535e 100644
--- a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
+++ b/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
@@ -16,6 +16,7 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.cts.jank.leanback.IntentKeys;
 import android.os.SystemClock;
 import android.support.test.jank.GfxMonitor;
@@ -40,9 +41,30 @@
     private final static String JAVA_PACKAGE = "android.cts.jank.leanback.ui";
     private final static String CLASS = JAVA_PACKAGE + ".MainActivity";
 
+    private boolean shouldSkip() {
+	PackageManager packageManager =
+                getInstrumentation().getTargetContext().getPackageManager();
+        if (!packageManager.hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected void runTest() throws Throwable {
+        if (shouldSkip()) {
+            return;
+        }
+        super.runTest();
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        if (shouldSkip()) {
+            return;
+        }
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setComponent(new ComponentName(APP_PACKAGE, CLASS));
 
diff --git a/tests/tests/netlegacy22/api/Android.mk b/tests/netlegacy22.api/Android.mk
similarity index 100%
rename from tests/tests/netlegacy22/api/Android.mk
rename to tests/netlegacy22.api/Android.mk
diff --git a/tests/tests/netlegacy22/api/AndroidManifest.xml b/tests/netlegacy22.api/AndroidManifest.xml
similarity index 92%
rename from tests/tests/netlegacy22/api/AndroidManifest.xml
rename to tests/netlegacy22.api/AndroidManifest.xml
index d243e45..f13805c 100644
--- a/tests/tests/netlegacy22/api/AndroidManifest.xml
+++ b/tests/netlegacy22.api/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.net.legacy22">
+    package="com.android.cts.netlegacy22.api">
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -30,7 +30,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.net.legacy22"
+                     android:targetPackage="com.android.cts.netlegacy22.api"
                      android:label="CTS tests of legacy android.net APIs as of API 22">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
similarity index 84%
rename from tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
rename to tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
index 8a9002b..1836f06 100644
--- a/tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
+++ b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
@@ -85,24 +85,58 @@
                 ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
     }
 
-    private void checkSourceAddress(String addrString, int type) throws Exception {
-        DatagramSocket d = new DatagramSocket();
-        d.connect(InetAddress.getByName(addrString), 7);
-        InetAddress localAddress = d.getLocalAddress();
-
+    // Returns a list of all the IP addresses for all the networks of a given legacy type. We can't
+    // just fetch the IP addresses for that type because there is no public getLinkProperties API
+    // that takes a legacy type.
+    private List<InetAddress> getIpAddresses(int type) {
+        ArrayList<InetAddress> addresses = new ArrayList<>();
         Network[] networks = mCm.getAllNetworks();
         for (int i = 0; i < networks.length; i++) {
             NetworkInfo ni = mCm.getNetworkInfo(networks[i]);
             if (ni != null && ni.getType() == type) {
+                // This does not include IP addresses on stacked interfaces (e.g., 464xlat), because
+                // there is no public API that will return them.
                 LinkProperties lp = mCm.getLinkProperties(networks[i]);
                 for (LinkAddress address : lp.getLinkAddresses()) {
-                    if (address.getAddress().equals(localAddress)) {
-                        return;
-                    }
+                    addresses.add(address.getAddress());
                 }
             }
         }
-        fail("Local address " + localAddress + " not assigned to any network of type " + type);
+        return addresses;
+    }
+
+    private boolean hasIPv4(int type) {
+        for (InetAddress address : getIpAddresses(type)) {
+            if (address instanceof Inet4Address) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void checkSourceAddress(String addrString, int type) throws Exception {
+        // The public requestRouteToHost API only supports IPv4, but it will not return failure if
+        // the network does not have an IPv4 address. So don't check that it's working unless we
+        // know that the network has an IPv4 address. Note that it's possible that the network will
+        // have an IPv4 address but we don't know about it, because the IPv4 address might be on a
+        // stacked interface and we wouldn't be able to see it.
+        if (!hasIPv4(type)) {
+            Log.d(TAG, "Not checking source address on network type " + type + ", no IPv4 address");
+            return;
+        }
+
+        DatagramSocket d = new DatagramSocket();
+        d.connect(InetAddress.getByName(addrString), 7);
+        InetAddress localAddress = d.getLocalAddress();
+        String localAddrString = localAddress.getHostAddress();
+
+        Log.d(TAG, "Got source address " + localAddrString + " for destination " + addrString);
+
+        assertTrue(
+                "Local address " + localAddress + " not assigned to any network of type " + type,
+                getIpAddresses(type).contains(localAddress));
+
+        Log.d(TAG, "Source address " + localAddress + " found on network type " + type);
     }
 
     /** Test that hipri can be brought up when Wifi is enabled. */
@@ -127,7 +161,6 @@
         assertTrue("Couldn't requestRouteToHost using HIPRI.",
                 mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
 
-        try { Thread.sleep(1000); } catch(Exception e) {}
         checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
         checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
 
diff --git a/tests/tests/netlegacy22/permission/Android.mk b/tests/netlegacy22.permission/Android.mk
similarity index 100%
rename from tests/tests/netlegacy22/permission/Android.mk
rename to tests/netlegacy22.permission/Android.mk
diff --git a/tests/tests/netlegacy22/permission/AndroidManifest.xml b/tests/netlegacy22.permission/AndroidManifest.xml
similarity index 89%
rename from tests/tests/netlegacy22/permission/AndroidManifest.xml
rename to tests/netlegacy22.permission/AndroidManifest.xml
index d407404..cd1d2ba 100644
--- a/tests/tests/netlegacy22/permission/AndroidManifest.xml
+++ b/tests/netlegacy22.permission/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.permission">
+    package="com.android.cts.netlegacy22.permission">
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <application>
@@ -41,8 +41,8 @@
         relies on hidden APIs.
     -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.permission"
-                     android:label="CTS tests of com.android.cts.permission">
+                     android:targetPackage="com.android.cts.netlegacy22.permission"
+                     android:label="CTS tests of legacy android.net permissions as of API 22">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java b/tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
similarity index 100%
rename from tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
rename to tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
diff --git a/tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java b/tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
similarity index 100%
rename from tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
rename to tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index ca20549..f5b29cf 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -332,6 +332,9 @@
                 .setTicker(message)
                 .setContentTitle("")
                 .setContentText("")
+                // Mark the notification as "interruptive" by specifying a vibration pattern. This
+                // ensures it's announced properly on watch-type devices.
+                .setVibrate(new long[] {})
                 .build();
 
         // create and populate the expected event
diff --git a/tests/tests/alarmclock/AndroidTest.xml b/tests/tests/alarmclock/AndroidTest.xml
index 1cdd7f4..aafdb61 100644
--- a/tests/tests/alarmclock/AndroidTest.xml
+++ b/tests/tests/alarmclock/AndroidTest.xml
@@ -17,7 +17,5 @@
     <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockService.apk" />
     <option name="run-command:run-command"
          value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
-    <option name="run-command:teardown-command"
-         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
     <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockTestCases.apk" />
 </configuration>
diff --git a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
index 0089e69..f41100a 100644
--- a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
+++ b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
@@ -23,6 +23,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.provider.AlarmClock;
 import android.os.Bundle;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
@@ -53,23 +55,61 @@
 
     @Override
     protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mActivityDoneReceiver);
+        if (mActivityDoneReceiver != null) {
+            try {
+                mContext.unregisterReceiver(mActivityDoneReceiver);
+            } catch (IllegalArgumentException e) {
+                // This exception is thrown if mActivityDoneReceiver in
+                // the above call to unregisterReceiver is never registered.
+                // If so, no harm done by ignoring this exception.
+            }
+            mActivityDoneReceiver = null;
+        }
         super.tearDown();
     }
 
     private void registerBroadcastReceiver(TestcaseType testCaseType) throws Exception {
         mTestCaseType = testCaseType;
         mLatch = new CountDownLatch(1);
-        if (mActivityDoneReceiver != null) {
-            mContext.unregisterReceiver(mActivityDoneReceiver);
-        }
         mActivityDoneReceiver = new ActivityDoneReceiver();
         mContext.registerReceiver(mActivityDoneReceiver,
                 new IntentFilter(Utils.BROADCAST_INTENT + testCaseType.toString()));
     }
 
+    private boolean isIntentSupported(TestcaseType testCaseType) {
+        Intent intent;
+        switch (testCaseType) {
+          case DISMISS_ALARM:
+              intent = new Intent(AlarmClock.ACTION_DISMISS_ALARM);
+              break;
+
+          case SET_ALARM:
+          case SET_ALARM_FOR_DISMISSAL:
+              intent = new Intent(AlarmClock.ACTION_SET_ALARM);
+              break;
+
+          case SNOOZE_ALARM:
+              intent = new Intent(AlarmClock.ACTION_SNOOZE_ALARM);
+              break;
+
+          default:
+              // shouldn't happen
+              return false;
+        }
+        final PackageManager manager = mContext.getPackageManager();
+        assertNotNull(manager);
+        if (manager.resolveActivity(intent, 0) == null) {
+            Log.i(TAG, "No Voice Activity found for the intent: " + intent.getAction());
+            return false;
+        }
+        return true;
+    }
+
     protected String runTest(TestcaseType testCaseType) throws Exception {
         Log.i(TAG, "Begin Testing: " + testCaseType);
+        // Make sure the corresponding intent is supported by the platform, before testing.
+        if (!isIntentSupported(testCaseType)) return Utils.COMPLETION_RESULT;
+
         if (!startTestActivity(testCaseType)) {
             fail("test activity start failed for testcase = " + testCaseType);
             return "";
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
index b6fef4a..bd96d76 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
@@ -20,6 +20,7 @@
 import android.app.usage.NetworkStatsManager;
 import android.app.usage.NetworkStats;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -39,7 +40,7 @@
 import java.net.URL;
 import java.text.MessageFormat;
 import java.util.Scanner;
-import javax.net.ssl.HttpsURLConnection;
+import java.net.HttpURLConnection;
 
 import libcore.io.IoUtils;
 import libcore.io.Streams;
@@ -50,20 +51,67 @@
     private static final String APPOPS_GET_SHELL_COMMAND = "appops get {0} {1}";
 
     private static final long MINUTE = 1000 * 60;
+    private static final int TIMEOUT_MILLIS = 15000;
 
-    private static final int[] sNetworkTypesToTest = new int[] {
-        ConnectivityManager.TYPE_WIFI,
-        ConnectivityManager.TYPE_MOBILE,
-    };
+    private interface NetworkInterfaceToTest {
+        int getNetworkType();
+        int getTransportType();
+        String getSystemFeature();
+        String getErrorMessage();
+    }
 
-    // Order corresponds to sNetworkTypesToTest
-    private static final int[] sTransportTypesToTest = new int[] {
-        NetworkCapabilities.TRANSPORT_WIFI,
-        NetworkCapabilities.TRANSPORT_CELLULAR,
+    private static final NetworkInterfaceToTest[] sNetworkInterfacesToTest =
+            new NetworkInterfaceToTest[] {
+                    new NetworkInterfaceToTest() {
+                        @Override
+                        public int getNetworkType() {
+                            return ConnectivityManager.TYPE_WIFI;
+                        }
+
+                        @Override
+                        public int getTransportType() {
+                            return NetworkCapabilities.TRANSPORT_WIFI;
+                        }
+
+                        @Override
+                        public String getSystemFeature() {
+                            return PackageManager.FEATURE_WIFI;
+                        }
+
+                        @Override
+                        public String getErrorMessage() {
+                            return " Please make sure you are connected to a WiFi access point.";
+                        }
+                    },
+                    new NetworkInterfaceToTest() {
+                        @Override
+                        public int getNetworkType() {
+                            return ConnectivityManager.TYPE_MOBILE;
+                        }
+
+                        @Override
+                        public int getTransportType() {
+                            return NetworkCapabilities.TRANSPORT_CELLULAR;
+                        }
+
+                        @Override
+                        public String getSystemFeature() {
+                            return PackageManager.FEATURE_TELEPHONY;
+                        }
+
+                        @Override
+                        public String getErrorMessage() {
+                            return " Please make sure you have added a SIM card with data plan to" +
+                                    " your phone, have enabled data over cellular and in case of" +
+                                    " dual SIM devices, have selected the right SIM " +
+                                    "for data connection.";
+                        }
+                    }
     };
 
     private NetworkStatsManager mNsm;
     private ConnectivityManager mCm;
+    private PackageManager mPm;
     private long mStartTime;
     private long mEndTime;
 
@@ -71,62 +119,49 @@
     private String mWriteSettingsMode;
     private String mUsageStatsMode;
 
-    private void exerciseRemoteHost(int transportType) throws Exception {
-        final int timeout = 15000;
-        mCm.requestNetwork(new NetworkRequest.Builder()
-            .addTransportType(transportType)
-            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-            .build(), new ConnectivityManager.NetworkCallback() {
-                @Override
-                public void onAvailable(Network network) {
-                    NetworkInfo networkInfo = mCm.getNetworkInfo(network);
-                    if (networkInfo == null) {
-                        Log.w(LOG_TAG, "Network info is null");
-                    } else {
-                        Log.w(LOG_TAG, "Network: " + networkInfo.toString());
-                    }
-                    InputStreamReader in = null;
-                    HttpsURLConnection urlc = null;
-                    String originalKeepAlive = System.getProperty("http.keepAlive");
-                    System.setProperty("http.keepAlive", "false");
-                    try {
-                        urlc = (HttpsURLConnection) network.openConnection(new URL(
-                                "https://www.google.com"));
-                        urlc.setConnectTimeout(timeout);
-                        urlc.setUseCaches(false);
-                        urlc.connect();
-                        boolean ping = urlc.getResponseCode() == 200;
-                        if (ping) {
-                            in = new InputStreamReader(
-                                    (InputStream) urlc.getContent());
-
-                            mBytesRead = 0;
-                            while (in.read() != -1) ++mBytesRead;
-                        }
-                    } catch (Exception e) {
-                        Log.i(LOG_TAG, "Badness during exercising remote server: " + e);
-                    } finally {
-                        if (in != null) {
-                            try {
-                                in.close();
-                            } catch (IOException e) {
-                                // don't care
-                            }
-                        }
-                        if (urlc != null) {
-                            urlc.disconnect();
-                        }
-                        if (originalKeepAlive == null) {
-                            System.clearProperty("http.keepAlive");
-                        } else {
-                            System.setProperty("http.keepAlive", originalKeepAlive);
-                        }
-                    }
-                }
-            });
+    private void exerciseRemoteHost(Network network) throws Exception {
+        NetworkInfo networkInfo = mCm.getNetworkInfo(network);
+        if (networkInfo == null) {
+            Log.w(LOG_TAG, "Network info is null");
+        } else {
+            Log.w(LOG_TAG, "Network: " + networkInfo.toString());
+        }
+        InputStreamReader in = null;
+        HttpURLConnection urlc = null;
+        String originalKeepAlive = System.getProperty("http.keepAlive");
+        System.setProperty("http.keepAlive", "false");
         try {
-            Thread.sleep(timeout);
-        } catch (InterruptedException e) {
+            urlc = (HttpURLConnection) network.openConnection(new URL(
+                    "http://www.265.com/"));
+            urlc.setConnectTimeout(TIMEOUT_MILLIS);
+            urlc.setUseCaches(false);
+            urlc.connect();
+            boolean ping = urlc.getResponseCode() == 200;
+            if (ping) {
+                in = new InputStreamReader(
+                        (InputStream) urlc.getContent());
+
+                mBytesRead = 0;
+                while (in.read() != -1) ++mBytesRead;
+            }
+        } catch (Exception e) {
+            Log.i(LOG_TAG, "Badness during exercising remote server: " + e);
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    // don't care
+                }
+            }
+            if (urlc != null) {
+                urlc.disconnect();
+            }
+            if (originalKeepAlive == null) {
+                System.clearProperty("http.keepAlive");
+            } else {
+                System.setProperty("http.keepAlive", originalKeepAlive);
+            }
         }
     }
 
@@ -139,6 +174,8 @@
         mCm = (ConnectivityManager) getInstrumentation().getContext()
                 .getSystemService(Context.CONNECTIVITY_SERVICE);
 
+        mPm = getInstrumentation().getContext().getPackageManager();
+
         mWriteSettingsMode = getAppOpsMode(AppOpsManager.OPSTR_WRITE_SETTINGS);
         setAppOpsMode(AppOpsManager.OPSTR_WRITE_SETTINGS, "allow");
         mUsageStatsMode = getAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS);
@@ -190,19 +227,65 @@
         }
     }
 
-    private boolean shouldTestThisNetworkType(int networkTypeIndex, long tolerance)
-            throws Exception {
-        NetworkInfo networkInfo = mCm.getNetworkInfo(sNetworkTypesToTest[networkTypeIndex]);
-        if (networkInfo == null || !networkInfo.isAvailable()) {
-            return false;
+    private class NetworkCallback extends ConnectivityManager.NetworkCallback {
+        private long mTolerance;
+        public boolean success;
+
+        NetworkCallback(long tolerance) {
+            mTolerance = tolerance;
+            success = false;
         }
-        mStartTime = System.currentTimeMillis() - tolerance;
-        exerciseRemoteHost(sTransportTypesToTest[networkTypeIndex]);
-        mEndTime = System.currentTimeMillis() + tolerance;
-        return true;
+
+        @Override
+        public void onAvailable(Network network) {
+            try {
+                mStartTime = System.currentTimeMillis() - mTolerance;
+                exerciseRemoteHost(network);
+                mEndTime = System.currentTimeMillis() + mTolerance;
+                success = true;
+                synchronized(NetworkUsageStatsTest.this) {
+                    NetworkUsageStatsTest.this.notify();
+                }
+            } catch (Exception e) {
+                Log.w(LOG_TAG, "exercising remote host failed.", e);
+                success = false;
+            }
+        }
     }
 
-    private String getSubscriberId(int networkType) {
+    private boolean shouldTestThisNetworkType(int networkTypeIndex, final long tolerance)
+            throws Exception {
+        boolean hasFeature = mPm.hasSystemFeature(
+                sNetworkInterfacesToTest[networkTypeIndex].getSystemFeature());
+        if (!hasFeature) {
+            return false;
+        }
+        NetworkCallback callback = new NetworkCallback(tolerance);
+        mCm.requestNetwork(new NetworkRequest.Builder()
+                .addTransportType(sNetworkInterfacesToTest[networkTypeIndex].getTransportType())
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build(), callback);
+        synchronized(this) {
+            try {
+                wait((int)(TIMEOUT_MILLIS * 1.2));
+            } catch (InterruptedException e) {
+            }
+        }
+        if (callback.success) {
+            return true;
+        }
+
+        // This will always fail at this point as we know 'hasFeature' is true.
+        assertFalse (sNetworkInterfacesToTest[networkTypeIndex].getSystemFeature() +
+                " is a reported system feature, " +
+                "however no corresponding connected network interface was found or the attempt " +
+                "to connect has timed out (timeout = " + TIMEOUT_MILLIS + "ms)." +
+                sNetworkInterfacesToTest[networkTypeIndex].getErrorMessage(), hasFeature);
+        return false;
+    }
+
+    private String getSubscriberId(int networkIndex) {
+        int networkType = sNetworkInterfacesToTest[networkIndex].getNetworkType();
         if (ConnectivityManager.TYPE_MOBILE == networkType) {
             TelephonyManager tm = (TelephonyManager) getInstrumentation().getContext()
                     .getSystemService(Context.TELEPHONY_SERVICE);
@@ -212,7 +295,7 @@
     }
 
     public void testDeviceSummary() throws Exception {
-        for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+        for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
             if (!shouldTestThisNetworkType(i, MINUTE/2)) {
                 continue;
             }
@@ -220,7 +303,7 @@
             NetworkStats.Bucket bucket = null;
             try {
                 bucket = mNsm.querySummaryForDevice(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
             } catch (RemoteException | SecurityException e) {
                 fail("testDeviceSummary fails with exception: " + e.toString());
@@ -232,7 +315,7 @@
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 bucket = mNsm.querySummaryForDevice(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
                 fail("negative testDeviceSummary fails: no exception thrown.");
             } catch (RemoteException e) {
@@ -244,7 +327,7 @@
     }
 
     public void testUserSummary() throws Exception {
-        for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+        for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
             if (!shouldTestThisNetworkType(i, MINUTE/2)) {
                 continue;
             }
@@ -252,7 +335,7 @@
             NetworkStats.Bucket bucket = null;
             try {
                 bucket = mNsm.querySummaryForUser(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
             } catch (RemoteException | SecurityException e) {
                 fail("testUserSummary fails with exception: " + e.toString());
@@ -264,7 +347,7 @@
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 bucket = mNsm.querySummaryForUser(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
                 fail("negative testUserSummary fails: no exception thrown.");
             } catch (RemoteException e) {
@@ -276,7 +359,7 @@
     }
 
     public void testAppSummary() throws Exception {
-        for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+        for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
             if (!shouldTestThisNetworkType(i, MINUTE/2)) {
                 continue;
             }
@@ -284,7 +367,7 @@
             NetworkStats result = null;
             try {
                 result = mNsm.querySummary(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
                 assertTrue(result != null);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -317,7 +400,7 @@
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 result = mNsm.querySummary(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
                 fail("negative testAppSummary fails: no exception thrown.");
             } catch (RemoteException e) {
@@ -329,7 +412,7 @@
     }
 
     public void testAppDetails() throws Exception {
-        for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+        for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
             // Relatively large tolerance to accommodate for history bucket size.
             if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
                 continue;
@@ -338,7 +421,7 @@
             NetworkStats result = null;
             try {
                 result = mNsm.queryDetails(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
                 assertTrue(result != null);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -372,7 +455,7 @@
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 result = mNsm.queryDetails(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
                 fail("negative testAppDetails fails: no exception thrown.");
             } catch (RemoteException e) {
@@ -384,7 +467,7 @@
     }
 
     public void testUidDetails() throws Exception {
-        for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+        for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
             // Relatively large tolerance to accommodate for history bucket size.
             if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
                 continue;
@@ -393,7 +476,7 @@
             NetworkStats result = null;
             try {
                 result = mNsm.queryDetailsForUid(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime, Process.myUid());
                 assertTrue(result != null);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -426,7 +509,7 @@
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 result = mNsm.queryDetailsForUid(
-                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime, Process.myUid());
                 fail("negative testUidDetails fails: no exception thrown.");
             } catch (RemoteException e) {
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
index dfa278a..c8ef253 100644
--- a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
+++ b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.DisplayMetrics;
@@ -40,6 +41,8 @@
     }
 
     public static class ExpectedMemorySizesClass {
+        private static final Map<Integer, Integer> expectedMemorySizeForWatch
+            =  new HashMap<Integer, Integer>();
         private static final Map<Integer, Integer> expectedMemorySizeForSmallNormalScreen
             =  new HashMap<Integer, Integer>();
         private static final Map<Integer, Integer> expectedMemorySizeForLargeScreen
@@ -48,6 +51,21 @@
             =  new HashMap<Integer, Integer>();
 
         static {
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_LOW, 32);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_MEDIUM, 32);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_TV, 32);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_HIGH, 36);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_280, 36);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XHIGH, 48);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_360, 48);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_400, 56);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_420, 64);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXHIGH, 88);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_560, 112);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXXHIGH, 154);
+        }
+
+        static {
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_LOW, 32);
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_MEDIUM, 32);
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_TV, 48);
@@ -92,7 +110,15 @@
             expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 768);
         }
 
-        public static Integer getExpectedMemorySize(int screenSize, int screenDensity) {
+        public static Integer getExpectedMemorySize(
+                int screenSize,
+                int screenDensity,
+                boolean isWatch) {
+
+           if (isWatch) {
+              return expectedMemorySizeForWatch.get(screenDensity);
+           }
+
            switch (screenSize) {
                 case Configuration.SCREENLAYOUT_SIZE_SMALL:
                 case Configuration.SCREENLAYOUT_SIZE_NORMAL:
@@ -141,8 +167,11 @@
     }
 
     private void assertMemoryForScreenDensity(int memoryClass, int screenDensity, int screenSize) {
-        int expectedMinimumMemory = ExpectedMemorySizesClass.getExpectedMemorySize(screenSize,
-                                                                                   screenDensity);
+        Context context = getInstrumentation().getTargetContext();
+        boolean isWatch =
+            context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+        int expectedMinimumMemory =
+            ExpectedMemorySizesClass.getExpectedMemorySize(screenSize, screenDensity, isWatch);
 
         assertTrue("Expected to have at least " + expectedMinimumMemory
                 + "mb of memory for screen density " + screenDensity,
diff --git a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
index 5781442..fbb3060 100644
--- a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -74,9 +74,8 @@
         sendNotification(id, R.drawable.black);
         mNotificationManager.cancel(id);
 
-        StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
-        for (StatusBarNotification sbn : sbns) {
-            assertFalse("canceled notification was still alive, id=" + id, sbn.getId() == id);
+        if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
+            fail("canceled notification was still alive, id=" + id);
         }
     }
 
@@ -116,10 +115,31 @@
                 .build();
         mNotificationManager.notify(id, notification);
 
-        StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
-        for (StatusBarNotification sbn : sbns) {
-            if (sbn.getId() == id) return;
+
+        if (!checkNotificationExistence(id, /*shouldExist=*/ true)) {
+            fail("couldn't find posted notification id=" + id);
         }
-        fail("couldn't find posted notification id=" + id);
+    }
+
+    private boolean checkNotificationExistence(int id, boolean shouldExist) {
+        // notification is a bit asynchronous so it may take a few ms to appear in getActiveNotifications()
+        // we will check for it for up to 200ms before giving up
+        boolean found = false;
+        for (int tries=3; tries-->0;) {
+            final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                if (sbn.getId() == id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (found == shouldExist) break;
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                // pass
+            }
+        }
+        return found == shouldExist;
     }
 }
diff --git a/tests/tests/assist/AndroidManifest.xml b/tests/tests/assist/AndroidManifest.xml
index fefdf54..a81ced2 100644
--- a/tests/tests/assist/AndroidManifest.xml
+++ b/tests/tests/assist/AndroidManifest.xml
@@ -20,17 +20,22 @@
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
+    <uses-permission android:name="android.permission.INTERNET" />
 
     <application>
       <uses-library android:name="android.test.runner" />
       <activity android:name="android.assist.cts.TestStartActivity"
-                android:label="Assist Structure Test App"
-                android:theme="@android:style/Theme.Material.Light">
+                android:label="Assist Test Start Activity">
           <intent-filter>
               <action android:name="android.intent.action.TEST_START_ACTIVITY_ASSIST_STRUCTURE" />
               <action android:name="android.intent.action.TEST_START_ACTIVITY_DISABLE_CONTEXT" />
               <action android:name="android.intent.action.TEST_START_ACTIVITY_FLAG_SECURE" />
               <action android:name="android.intent.action.TEST_START_ACTIVITY_LIFECYCLE" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_SCREENSHOT" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_EXTRA_ASSIST" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_TEXTVIEW" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_LARGE_VIEW_HIERARCHY" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_WEBVIEW" />
               <category android:name="android.intent.category.LAUNCHER" />
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
diff --git a/tests/tests/assist/AndroidTest.xml b/tests/tests/assist/AndroidTest.xml
index f7c56ad..329692d 100644
--- a/tests/tests/assist/AndroidTest.xml
+++ b/tests/tests/assist/AndroidTest.xml
@@ -19,7 +19,5 @@
     <option name="cts-apk-installer:test-file-name" value="CtsAssistApp.apk" />
     <option name="run-command:run-command"
          value="settings put secure voice_interaction_service android.assist.service/.MainInteractionService" />
-    <option name="run-command:teardown-command"
-         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
     <option name="cts-apk-installer:test-file-name" value="CtsAssistTestCases.apk" />
 </configuration>
diff --git a/tests/tests/assist/common/src/android/assist/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
index 4bf9412..54416b4 100644
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -19,6 +19,8 @@
 import android.content.ComponentName;
 import android.os.Bundle;
 
+import org.json.JSONException;
+import org.json.JSONObject;
 import java.util.ArrayList;
 
 public class Utils {
@@ -29,13 +31,24 @@
     public static final String BROADCAST_ASSIST_DATA_INTENT = ACTION_PREFIX + "ASSIST_DATA";
     public static final String BROADCAST_INTENT_START_ASSIST = ACTION_PREFIX + "START_ASSIST";
     public static final String ASSIST_RECEIVER_REGISTERED = ACTION_PREFIX + "ASSIST_READY";
+
+    public static final String ACTION_INVALIDATE = "invalidate_action";
+    public static final String GET_CONTENT_VIEW_HEIGHT = ACTION_PREFIX + "GET_CONTENT_VIEW_HEIGHT";
+    public static final String BROADCAST_CONTENT_VIEW_HEIGHT = ACTION_PREFIX + "VIEW_HEIGHT";
+    public static final String SCROLL_TEXTVIEW_ACTION = ACTION_PREFIX + "TEXTVIEW_SCROLL";
+    public static final String SCROLL_SCROLLVIEW_ACTION = ACTION_PREFIX + "SCROLLVIEW_SCROLL";
     public static final String TEST_ERROR = "Error In Test:";
 
     public static final String ASSIST_STRUCTURE_KEY = "assist_structure";
     public static final String ASSIST_CONTENT_KEY = "assist_content";
     public static final String ASSIST_BUNDLE_KEY = "assist_bundle";
     public static final String ASSIST_SCREENSHOT_KEY = "assist_screenshot";
-
+    public static final String SCREENSHOT_COLOR_KEY = "set_screenshot_color";
+    public static final String COMPARE_SCREENSHOT_KEY = "compare_screenshot";
+    public static final String DISPLAY_WIDTH_KEY = "display_width";
+    public static final String DISPLAY_HEIGHT_KEY = "dislay_height";
+    public static final String SCROLL_X_POSITION = "scroll_x_position";
+    public static final String SCROLL_Y_POSITION = "scroll_y_position";
 
     /** Lifecycle Test intent constants */
     public static final String LIFECYCLE_PREFIX = ACTION_PREFIX + "lifecycle_";
@@ -44,35 +57,103 @@
     public static final String LIFECYCLE_ONSTOP = LIFECYCLE_PREFIX + "onstop";
     public static final String LIFECYCLE_ONDESTROY = LIFECYCLE_PREFIX + "ondestroy";
 
+    /** Focus Change Test intent constants */
+    public static final String GAINED_FOCUS = ACTION_PREFIX + "focus_changed";
+    public static final String LOST_FOCUS = ACTION_PREFIX + "lost_focus";
+
     /** Flag Secure Test intent constants */
     public static final String FLAG_SECURE_HASRESUMED = ACTION_PREFIX + "flag_secure_hasResumed";
-    public static final String ASSIST_STRUCTURE_HASRESUMED = ACTION_PREFIX
-            + "assist_structure_hasResumed";
+    public static final String APP_3P_HASRESUMED = ACTION_PREFIX + "app_3p_hasResumed";
+    public static final String TEST_ACTIVITY_LOADED = ACTION_PREFIX + "test_activity_hasResumed";
 
     /** Two second timeout for getting back assist context */
     public static final int TIMEOUT_MS = 2 * 1000;
+    /** Four second timeout for an activity to resume */
     public static final int ACTIVITY_ONRESUME_TIMEOUT_MS = 4000;
+
     public static final String EXTRA_REGISTER_RECEIVER = "register_receiver";
 
+    /** Extras for passing the Assistant's ContentView's dimensions*/
+    public static final String EXTRA_CONTENT_VIEW_HEIGHT = "extra_content_view_height";
+    public static final String EXTRA_CONTENT_VIEW_WIDTH = "extra_content_view_width";
+    public static final String EXTRA_DISPLAY_POINT = "extra_display_point";
+
     /** Test name suffixes */
     public static final String ASSIST_STRUCTURE = "ASSIST_STRUCTURE";
     public static final String DISABLE_CONTEXT = "DISABLE_CONTEXT";
     public static final String FLAG_SECURE = "FLAG_SECURE";
     public static final String LIFECYCLE = "LIFECYCLE";
+    public static final String SCREENSHOT = "SCREENSHOT";
+    public static final String EXTRA_ASSIST = "EXTRA_ASSIST";
+    public static final String VERIFY_CONTENT_VIEW = "VERIFY_CONTENT_VIEW";
+    public static final String TEXTVIEW = "TEXTVIEW";
+    public static final String LARGE_VIEW_HIERARCHY = "LARGE_VIEW_HIERARCHY";
+    public static final String WEBVIEW = "WEBVIEW";
+    public static final String FOCUS_CHANGE = "FOCUS_CHANGE";
 
     /** Session intent constants */
     public static final String HIDE_SESSION = "android.intent.action.hide_session";
 
-    /**
-     * The shim activity that starts the service associated with each test.
-     */
+    /** Stub html view to load into WebView */
+    public static final String WEBVIEW_HTML_GREETING = "Hello WebView!";
+    public static final String WEBVIEW_HTML = "<html><body><div><p>" + WEBVIEW_HTML_GREETING
+            + "</p></div></body></html>";
+
+    /** Extra data to add to assist data and assist content */
+    private static Bundle EXTRA_ASSIST_BUNDLE;
+    private static String STRUCTURED_JSON;
+
+    public static final String getStructuredJSON() throws Exception {
+        if (STRUCTURED_JSON == null) {
+            STRUCTURED_JSON = new JSONObject()
+                    .put("@type", "MusicRecording")
+                    .put("@id", "https://example/music/recording")
+                    .put("url", "android-app://com.example/https/music/album")
+                    .put("name", "Album Title")
+                    .put("hello", "hi there")
+                    .put("knownNull", null)
+                    .put("unicode value", "\ud800\udc35")
+                    .put("empty string", "")
+                    .put("LongString",
+                        "lkasdjfalsdkfjalsdjfalskj9i9234jl1w23j4o123j412l3j421l3kj412l3kj1l3k4j32")
+                    .put("\ud800\udc35", "any-value")
+                    .put("key with spaces", "any-value")
+                    .toString();
+        }
+        return STRUCTURED_JSON;
+    }
+
+    public static final Bundle getExtraAssistBundle() {
+        if (EXTRA_ASSIST_BUNDLE == null) {
+            EXTRA_ASSIST_BUNDLE = new Bundle();
+            addExtraAssistDataToBundle(EXTRA_ASSIST_BUNDLE);
+        }
+        return EXTRA_ASSIST_BUNDLE;
+    }
+
+    public static void addExtraAssistDataToBundle(Bundle data) {
+        data.putString("hello", "there");
+        data.putBoolean("isthis_true_or_false", true);
+        data.putInt("number", 123);
+    }
+
+    /** The shim activity that starts the service associated with each test. */
     public static final String getTestActivity(String testCaseType) {
         switch (testCaseType) {
             case DISABLE_CONTEXT:
+                // doesn't need to wait for activity to resume
+                // can be activated on top of any non-secure activity.
                 return "service.DisableContextActivity";
             case ASSIST_STRUCTURE:
             case FLAG_SECURE:
             case LIFECYCLE:
+            case SCREENSHOT:
+            case EXTRA_ASSIST:
+            case VERIFY_CONTENT_VIEW:
+            case TEXTVIEW:
+            case LARGE_VIEW_HIERARCHY:
+            case WEBVIEW:
+            case FOCUS_CHANGE:
                 return "service.DelayedAssistantActivity";
             default:
                 return "";
@@ -85,22 +166,51 @@
     public static final ComponentName getTestAppComponent(String testCaseType) {
         switch (testCaseType) {
             case ASSIST_STRUCTURE:
+            case LARGE_VIEW_HIERARCHY:
                 return new ComponentName(
                         "android.assist.testapp", "android.assist.testapp.TestApp");
             case DISABLE_CONTEXT:
                 return new ComponentName(
-                        "android.assist.testapp", "android.assist.testapp.DisableContextActivity");
+                        "android.assist.testapp", "android.assist.testapp.TestApp");
             case FLAG_SECURE:
                 return new ComponentName(
                         "android.assist.testapp", "android.assist.testapp.SecureActivity");
             case LIFECYCLE:
                 return new ComponentName(
                         "android.assist.testapp", "android.assist.testapp.LifecycleActivity");
+            case SCREENSHOT:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.ScreenshotActivity");
+            case EXTRA_ASSIST:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.ExtraAssistDataActivity");
+            case TEXTVIEW:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.TextViewActivity");
+            case WEBVIEW:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.WebViewActivity");
+            case FOCUS_CHANGE:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.FocusChangeActivity");
             default:
                 return new ComponentName("","");
         }
     }
 
+    /**
+     * Returns the amount of time to wait for assist data.
+     */
+    public static final int getAssistDataTimeout(String testCaseType) {
+        switch (testCaseType) {
+            case SCREENSHOT:
+                // needs to wait for 3p activity to resume before receiving assist data.
+                return TIMEOUT_MS + ACTIVITY_ONRESUME_TIMEOUT_MS;
+            default:
+                return TIMEOUT_MS;
+        }
+    }
+
     public static final String toBundleString(Bundle bundle) {
         if (bundle == null) {
             return "*** Bundle is null ****";
diff --git a/tests/tests/assist/res/layout/multiple_text_views.xml b/tests/tests/assist/res/layout/multiple_text_views.xml
new file mode 100644
index 0000000..455d5e3
--- /dev/null
+++ b/tests/tests/assist/res/layout/multiple_text_views.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:orientation="vertical">
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <ScrollView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1">
+    <TextView
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:scrollbars="vertical"
+      android:text="@string/text_too_large_to_fit" />
+  </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/layout/screenshot_activity.xml b/tests/tests/assist/res/layout/screenshot_activity.xml
new file mode 100644
index 0000000..05051dc
--- /dev/null
+++ b/tests/tests/assist/res/layout/screenshot_activity.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/screenshot_activity"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/layout/text_view.xml b/tests/tests/assist/res/layout/text_view.xml
new file mode 100644
index 0000000..9964ab6
--- /dev/null
+++ b/tests/tests/assist/res/layout/text_view.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:orientation="vertical">
+    <TextView
+        android:id="@+id/text_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:focusable="false"
+        android:focusableInTouchMode="false"
+        android:scrollbars="vertical"
+        android:clickable="true"
+        android:text="@string/text_too_large_to_fit" />
+
+    <ScrollView
+        android:id="@+id/scroll_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:scrollbars="vertical"
+            android:text="@string/text_too_large_to_fit" />
+    </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/layout/webview.xml b/tests/tests/assist/res/layout/webview.xml
new file mode 100644
index 0000000..bdb8082
--- /dev/null
+++ b/tests/tests/assist/res/layout/webview.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <WebView
+        android:id="@+id/webview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    </WebView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/values/strings.xml b/tests/tests/assist/res/values/strings.xml
index ae4f16e..8170d70 100644
--- a/tests/tests/assist/res/values/strings.xml
+++ b/tests/tests/assist/res/values/strings.xml
@@ -15,4 +15,270 @@
 -->
 <resources>
     <string name="welcome">Hello there!</string>
+    <string name="testAppTitle">Assist Structure Test Activity</string>
+    <string name="screenshotActivityTitle">Screenshot Test Activity</string>
+    <string name="textViewActivityTitle">TextView Test Activity</string>
+    <string name="webViewActivityTitle">WebView Test Activity</string>
+    <string name="text_too_large_to_fit">❤ ☀ ☆ ☂ ☻ ♞ ☯ ☭ ☢ € →Hello هتاف للترحيب שלום
+        përshëndetje Добры дзень 您好 হ্যালো здравей მიესალმები Χαίρετε હેલો नमस्ते Nnọọ こんにちは ಹಲೋ
+        Сәлеметсіз бе ជំរាបសួរ 안녕하세요 ສະບາຍດີ ഹലോ हॅलो Сайн байна уу नमस्ते سلامהעלא ہیلو
+        မင်္ဂလာပါ ਸਤ ਸ੍ਰੀ ਅਕਾਲ Здравствуйте здраво ආයුබෝවන් ஹலோ హలో สวัสดี Pẹlẹ o
+        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+        convallis nunc et vestibulum. Sed et consequat quam, blandit varius tortor. Curabitur
+        accumsan nulla lectus, placerat condimentum odio elementum vel. Nulla erat ex, accumsan ut
+        enim sagittis, scelerisque efficitur ante. Nullam quis orci nec magna maximus malesuada ac
+        id sem. Nam sagittis erat risus, a accumsan neque congue sit amet. Nullam risus velit,
+        faucibus eget scelerisque et, maximus eget arcu. Sed porta sed libero ac imperdiet.
+
+        Nulla sem lectus, ullamcorper id dui vel, rutrum interdum augue. Proin aliquam nisi vitae
+        hendrerit tempor. Mauris porttitor velit et egestas feugiat. Vivamus eu dapibus libero,
+        quis fringilla urna. Suspendisse non turpis dui. Vivamus facilisis diam vitae est auctor
+        luctus. Etiam quis lectus viverra, interdum turpis eu, aliquam sem. Nulla vulputate lacinia
+        nisi a dictum. Cras faucibus vitae tortor at ullamcorper. Quisque sit amet sapien maximus,
+        ornare nisi non, imperdiet magna. Vestibulum tempor metus ac mi ultrices dapibus.
+
+        Suspendisse potenti. Mauris pellentesque lacinia tristique. Pellentesque vel dui quis sem
+        lacinia imperdiet feugiat vitae sem. Proin a arcu magna. Sed quis augue eu mi accumsan
+        pellentesque pretium in leo. Duis euismod purus mauris, ac tempor erat auctor non. Quisque
+        bibendum est pulvinar ex dapibus, ac tincidunt nibh tempus. Mauris sodales sem id purus
+        commodo iaculis. Pellentesque a quam dapibus, vehicula lectus at, tincidunt arcu. In
+        placerat porttitor urna quis consequat. Nullam feugiat nisl sed urna hendrerit, sed
+        elementum massa iaculis. Fusce sit amet turpis hendrerit, varius lorem sed, luctus mi.
+        Phasellus sit amet ex orci. Duis scelerisque nisl quis efficitur maximus. Curabitur vitae
+        accumsan nunc, eget varius nisi.
+
+        Fusce efficitur malesuada luctus. Aliquam dapibus tortor sit amet purus semper, sit amet
+        pretium lorem feugiat. Maecenas gravida sed arcu et placerat. Nulla facilisi. Cras placerat
+        rutrum mi, in rutrum mauris maximus at. Mauris eu suscipit ante. Nullam pharetra egestas
+        diam a viverra. Donec sem turpis, tempor malesuada est vel, blandit accumsan magna. In
+        iaculis velit in efficitur hendrerit. Nulla facilisi. Curabitur eget ligula lorem. Sed sit
+        amet dolor ut ligula malesuada condimentum. Phasellus molestie augue eget libero commodo,
+        vel blandit ex blandit.
+
+        Morbi cursus tortor ante, et tempus nisi tempus et. Suspendisse quis gravida diam. Aliquam
+        efficitur dolor sit amet sollicitudin varius. Etiam libero purus, ornare nec nulla vel,
+        ullamcorper blandit nisl. Sed vel consequat diam, id placerat sem. Donec quis elementum
+        urna. In posuere bibendum nunc, in condimentum justo blandit ac. Quisque enim lorem,
+        gravida at purus at, sollicitudin imperdiet erat. Ut consectetur rutrum ante, et pretium
+        odio iaculis a. Nullam a nibh vulputate, volutpat lectus eu, pellentesque felis. Nam
+        vehicula suscipit diam nec convallis. Quisque congue maximus sem, sit amet hendrerit leo
+        tempor et.
+
+        Nam eu consequat dui. Sed semper dignissim mattis. Integer tortor eros, tempor in lectus a,
+        lobortis aliquam dolor. Phasellus at sagittis magna. Nulla eleifend orci ac urna auctor,
+        sit amet luctus urna vulputate. Nulla venenatis venenatis erat ac finibus. Etiam
+        ullamcorper elementum suscipit. Morbi nec velit non mauris porta finibus. Nullam in
+        sagittis odio. Praesent eget nisl ut mauris vestibulum feugiat. Sed vulputate at elit et
+        cursus. Praesent viverra erat blandit nunc egestas, vel feugiat ex condimentum. Class
+        aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+
+        Nulla fermentum mattis urna, non gravida eros vestibulum et. Fusce porttitor augue turpis,
+        sit amet aliquam augue sodales non. Nunc neque odio, sagittis sed gravida euismod, commodo
+        at libero. Donec porttitor pulvinar neque vitae lobortis. Aliquam accumsan velit nec sapien
+        placerat egestas. Aliquam at tincidunt massa, et dignissim justo. Donec sapien ante, rutrum
+        et tristique a, commodo a massa.
+
+        Nunc placerat lobortis magna, et molestie lacus semper porta. Lorem ipsum dolor sit amet,
+        consectetur adipiscing elit. Phasellus ac ligula dui. Duis ultrices viverra eros fermentum
+        finibus. Integer ultrices, felis in accumsan volutpat, mi ligula hendrerit nunc, nec
+        accumsan mauris tellus sit amet metus. Ut pharetra enim et sapien sollicitudin, nec
+        ultricies urna pharetra. Morbi non tortor nec dui feugiat rutrum. Aliquam malesuada sodales
+        risus, sed congue nunc accumsan vitae. Etiam nunc magna, tempus non suscipit eu, feugiat ut
+        nibh. Maecenas et libero ut nisl pellentesque tempor nec vel quam. Etiam sem ligula,
+        ullamcorper non dolor a, viverra placerat nulla. Nullam dictum commodo dui, sed ultrices
+        enim sagittis eget. Morbi non consectetur lectus. In gravida, augue vitae pulvinar
+        molestie, ligula orci vulputate ex, at bibendum urna felis nec nibh. Sed nisl nunc, iaculis
+        at augue venenatis, fringilla accumsan velit. Curabitur nec augue porttitor, rutrum nisi
+        vitae, elementum orci.
+
+        Vestibulum eu tortor iaculis, dignissim velit quis, rhoncus dolor. Donec et tincidunt
+        nulla. Duis faucibus auctor erat ac ultricies. In a fermentum mi. Fusce vitae mi id sem
+        interdum tincidunt. Nulla hendrerit orci turpis, in maximus elit mollis eget. Aliquam erat
+        volutpat. Phasellus mattis est nibh, ut scelerisque ligula egestas eu. Ut molestie orci a
+        malesuada tempor. Sed tempus arcu id orci gravida faucibus. Vivamus ac lacinia neque, at
+        vehicula magna.
+
+        Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+        Nullam aliquam, justo scelerisque egestas sodales, purus odio posuere arcu, ac ultrices
+        nunc felis non massa. Aliquam vulputate ipsum sed aliquet auctor. In pulvinar, eros sit
+        amet ultricies tristique, lacus ipsum scelerisque eros, nec vestibulum est lectus quis
+        lorem. Pellentesque ac augue ut eros mattis viverra vitae ut lacus. Phasellus imperdiet
+        efficitur elit eget tincidunt. Donec sodales metus at dolor pulvinar, at gravida nibh
+        facilisis. Sed nec tellus luctus, cursus lacus sed, euismod orci. Maecenas sit amet leo
+        orci. Nulla non leo non mi eleifend consequat sit amet vitae dui. Sed gravida gravida
+        justo, tincidunt ultrices justo semper vitae. Fusce at nisi nisl. Morbi molestie quis justo
+        a convallis. Curabitur massa lacus, feugiat quis mauris ac, malesuada viverra est.
+
+        Phasellus bibendum faucibus velit, ac scelerisque velit tincidunt eu. Curabitur quis
+        suscipit erat, ac feugiat odio. Nullam et sapien et nibh maximus posuere. Vivamus faucibus
+        justo eget dictum sollicitudin. Etiam at leo eget elit facilisis lobortis. Maecenas
+        bibendum tortor non erat pretium dignissim. Fusce id imperdiet augue. Suspendisse dignissim
+        magna vel odio viverra varius. Maecenas suscipit ante et lorem sodales vehicula. Quisque
+        vel magna id sem suscipit iaculis. Etiam in elementum risus.
+
+        Suspendisse odio nisi, pharetra et purus sit amet, placerat lobortis diam. Phasellus enim
+        nunc, posuere sed porta in, ornare eu ipsum. Phasellus imperdiet porta neque, vitae dapibus
+        tellus feugiat eget. Nulla sodales leo ac efficitur luctus. Vivamus eget ipsum quis ante
+        pulvinar blandit. Vestibulum a justo convallis justo elementum viverra ut sit amet nisl.
+        Suspendisse eget augue fermentum, sagittis risus a, rhoncus elit. Vestibulum in maximus
+        tortor, non vestibulum libero. Nunc accumsan neque a nisl dapibus, id laoreet neque congue.
+        Pellentesque sapien odio, fringilla non nulla nec, varius placerat diam. Aliquam
+        consectetur neque eu ipsum posuere, nec dignissim sem faucibus. Donec sit amet tempor
+        sapien. Nam at libero vel lorem dapibus ultrices a vel augue. Nunc facilisis justo ante,
+        mollis tristique velit aliquet quis. Mauris consectetur odio at urna bibendum aliquam.
+
+           Nullam lectus orci, hendrerit ut ultrices in, dapibus pellentesque nibh. Aliquam arcu
+        metus, lobortis vel dignissim id, tempus ut ante. Integer vitae ante augue. In hac habitasse
+        platea dictumst. Vestibulum in tellus ante. Cras nisi tellus, congue ac velit quis, rhoncus
+        ornare ligula. Sed facilisis gravida pellentesque. Praesent id ultrices orci, ac ultricies
+        arcu. Donec at ante quis augue faucibus congue. Donec mattis quam dui, ut vestibulum orci
+        tempor mattis. Phasellus in quam id tortor varius ullamcorper ac ac ante. Proin cursus
+        accumsan sem, vel finibus lectus eleifend ut. Donec efficitur feugiat diam id ultricies. In
+        quis euismod nisi. Vestibulum eget viverra sapien. Donec scelerisque nec elit vel viverra.
+
+           Sed mi urna, rutrum quis augue vel, aliquet placerat diam. Proin faucibus in odio et
+        consequat. Proin ut ex in mauris eleifend efficitur. Praesent ullamcorper sollicitudin urna,
+        sed mollis elit hendrerit non. Duis leo lorem, efficitur eu auctor sit amet, scelerisque
+        scelerisque magna. Mauris eget massa auctor, viverra arcu a, elementum nibh. Sed
+        pellentesque, nulla sed condimentum posuere, tortor metus congue sem, nec placerat neque
+        magna vitae purus.
+
+           Etiam at risus vitae sapien aliquam condimentum. Vestibulum id libero placerat purus
+        vehicula consectetur. Pellentesque sapien sapien, posuere at pulvinar at, ultrices sed est.
+        Maecenas nec condimentum ante. Aenean volutpat, ex condimentum hendrerit hendrerit, quam
+        nisl  pharetra nibh, vitae bibendum nisl odio vel lacus. Morbi mi tellus, bibendum id mauris
+        eu,  facilisis volutpat turpis. Maecenas rutrum convallis felis. Quisque eget feugiat felis.
+        Duis pellentesque iaculis massa ut facilisis. Donec nec commodo magna. Integer aliquet orci
+        a odio eleifend elementum. Quisque molestie, urna ut molestie eleifend, odio neque maximus
+        enim, eget viverra metus lectus eget quam. Fusce nec urna ac neque bibendum aliquam vel quis
+        dui. Fusce ac quam consequat, feugiat leo vitae, auctor felis.
+
+           Sed ac metus mauris. Sed sed velit ut tortor aliquam vestibulum at eu arcu. Etiam eu
+        posuere lacus. Maecenas id lacus quis sem mollis sodales. Quisque justo sapien, vulputate ac
+        mi ut, congue vestibulum orci. Donec euismod erat rutrum, laoreet urna sed, accumsan purus.
+        Donec eu quam a sapien condimentum accumsan. Sed at tellus lorem. Curabitur bibendum, arcu
+        sit amet finibus sodales, mi sem finibus sem, eget scelerisque tellus neque vel urna.
+        Suspendisse eu augue nec erat suscipit luctus sed non metus.
+
+           Suspendisse porttitor ex ipsum. Pellentesque tristique eros sed pharetra porttitor.
+        Quisque ut elit vehicula, aliquet est nec, faucibus tellus. Donec ex augue, congue eu
+        dignissim  maximus, vestibulum at purus. Nulla quam enim, laoreet sit amet molestie vel,
+        dapibus nec tortor. Sed interdum massa ac orci gravida, vel viverra lacus lacinia. Donec
+        nisl lacus, fermentum at faucibus ac, consequat ut nibh. Praesent laoreet est augue, vitae
+        maximus dui efficitur sit amet. Cras ipsum tellus, tincidunt at volutpat non, tincidunt ut
+        elit. Morbi commodo sagittis gravida. Pellentesque sed ante massa. Phasellus a turpis non
+        turpis cursus consequat sed nec tortor. Proin et augue elit.
+
+           Duis finibus sem commodo rutrum pulvinar. In sollicitudin ante magna, vel facilisis
+        tellus fringilla vel. Nam purus ex, tincidunt eget varius at, euismod nec elit. Curabitur
+        consequat nulla vel nisi iaculis, ut mattis odio congue. Nulla et mollis tortor, a maximus
+        justo. Donec semper eros sed nunc rhoncus condimentum. Donec nibh purus, interdum non lectus
+        id, porta convallis eros.
+
+           Sed hendrerit, dui non sagittis sollicitudin, enim ex imperdiet sapien, et maximus lorem
+        dolor a enim. Nulla risus nisl, vestibulum at ornare posuere, congue in felis. Duis sagittis
+        id diam a varius. Donec viverra eu orci sodales commodo. Cras metus tortor, sodales vitae
+        auctor non, scelerisque a ante. Quisque sodales nisi libero, ut lobortis enim suscipit ut.
+        Cras mi ipsum, maximus non bibendum sit amet, pharetra quis ipsum. Vestibulum venenatis, odi
+        at hendrerit pretium, tellus diam auctor justo, non posuere quam mauris id nisl. Nam dolor
+        nibh, molestie et lectus et, scelerisque porta elit. Vestibulum viverra condimentum auctor.
+        In eros tortor, convallis sed quam eu, ultrices malesuada purus. Integer lorem quam,
+        ultricies at est consectetur, sagittis porttitor eros. Proin non risus vitae lacus
+        consectetur malesuada non pulvinar justo. Aliquam mollis nisi nunc, sit amet vulputate metus
+        sollicitudin vel.
+
+           Quisque auctor varius fermentum. Praesent mollis justo sit amet est consectetur, in
+        volutpat tellus mollis. Aenean at bibendum eros, at finibus nibh. Phasellus nec mi sem.
+        Mauris pellentesque dui sit amet lobortis aliquam. Ut nec massa at urna aliquam gravida vel
+        in magna. Donec consectetur sapien magna, a auctor sapien placerat eu.
+
+           Pellentesque aliquet ante sed lacus gravida rutrum. Maecenas euismod varius felis, nec
+        tempus metus tempus et. Nam convallis augue a massa scelerisque, vel pharetra dolor
+        scelerisque. Fusce porttitor mi a magna rutrum condimentum. Aliquam fermentum at turpis at
+        auctor. Nulla ut suscipit dui. Donec rutrum viverra aliquam. Donec elementum nisl sapien, ac
+        blandit risus porta facilisis. Proin tellus dolor, ornare vel magna sit amet, maximus
+        volutpat felis. Aenean euismod aliquet purus, at finibus nunc elementum eu. Ut faucibus
+        ullamcorper consectetur. Aenean egestas arcu id mauris elementum, at sollicitudin est
+        congue. Sed a odio mattis, sollicitudin erat ut, tristique dolor. Aliquam luctus risus quis
+        tellus semper, a vestibulum nulla viverra.
+
+           Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
+        himenaeos. Vestibulum sit amet nisi felis. Praesent condimentum consequat lacus pulvinar
+        imperdiet. Praesent vel condimentum quam. Maecenas eu aliquet odio. Vestibulum sed nulla
+        mattis lacus porta bibendum a ac eros. Nunc porttitor sagittis laoreet. Duis porta eros at
+        congue tristique. Pellentesque quis fringilla neque, a hendrerit tellus. Pellentesque ac
+        nibh ac tellus pulvinar porttitor et in est. Integer blandit lorem libero, eu pulvinar
+        tellus posuere eget. Vivamus pretium nulla ligula, ut dapibus massa fringilla in.
+        Suspendisse consectetur sem non elit porta, id pellentesque erat dapibus. Quisque ex mi,
+        tempus et hendrerit nec, gravida quis odio. Ut at mi in leo scelerisque venenatis.
+
+           Ut sed tellus in risus tincidunt tempor ut at arcu. Maecenas ut convallis justo. In
+        rutrum urna eu massa rhoncus, eget condimentum augue vehicula. Nullam eget placerat erat.
+        Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+        Aenean at volutpat orci, a lobortis dolor. Sed consequat facilisis interdum. Fusce libero
+        neque, fringilla in congue a, vehicula rutrum ipsum. Nam ornare placerat vestibulum. Proin
+        nec orci velit. Pellentesque scelerisque gravida diam, ut tristique libero tempus eu. Nam
+        semper lacus nec nulla volutpat imperdiet non eget tortor. Sed et pellentesque ligula.
+
+           Aenean a dolor dolor. Curabitur ut placerat lacus, sit amet aliquet orci. Aliquam erat
+        volutpat. Cras mollis sit amet lectus ornare pretium. Vestibulum fringilla orci vel est
+        iaculis, at mattis quam condimentum. Vivamus semper elit consectetur lectus gravida, in
+        sollicitudin mi fringilla. Donec eget lorem in orci blandit aliquam. Pellentesque libero
+        tellus, dignissim id augue et, vulputate viverra nisl. Cum sociis natoque penatibus et
+        magnis dis parturient montes, nascetur ridiculus mus. Donec ac vulputate metus, eu suscipit
+        sem. Donec placerat, nulla at sodales hendrerit, orci tortor vestibulum purus, non pharetra
+        nulla purus posuere arcu.
+
+           Quisque feugiat elit sem, ac interdum diam pharetra nec. Curabitur sem libero, vulputate
+        eu libero vitae, volutpat facilisis ligula. Aenean maximus erat laoreet, interdum ante in,
+        ultrices nisi. Nullam nec efficitur sapien. Integer feugiat et tortor ac bibendum. Donec a
+        scelerisque tortor. Cras quis viverra diam, vitae viverra ipsum. Aliquam ultrices neque sem,
+        congue sodales elit tempus sit amet. Pellentesque habitant morbi tristique senectus et netus
+        et malesuada fames ac turpis egestas. Sed dignissim ipsum eget diam rhoncus, ut finibus
+        nulla pretium. Morbi suscipit nibh vel nisl posuere molestie. Maecenas posuere turpis et
+        rutrum consectetur. Morbi venenatis arcu non gravida vulputate. Vivamus auctor tellus
+        ullamcorper ligula vestibulum cursus. Nunc gravida sit amet nisl quis facilisis.
+
+           Praesent ut justo vestibulum, accumsan mi et, feugiat purus. Nullam pulvinar iaculis
+        pharetra. Aliquam pulvinar risus sit amet elit suscipit tincidunt. In hac habitasse platea
+        dictumst. Etiam eget velit ac magna lacinia efficitur. Vestibulum ante ipsum primis in
+        faucibus orci luctus et ultrices posuere cubilia Curae; Cras volutpat tempus sollicitudin.
+        Ut et ante elit.
+
+           Sed ac tortor justo. Fusce sed metus libero. Duis sagittis tortor ac ante sollicitudin,
+        nec efficitur nibh euismod. Donec porttitor cursus quam, in aliquam lorem feugiat ut.
+        Aliquam tempor lacus eu feugiat feugiat. Nunc pulvinar, libero at auctor commodo, metus diam
+        commodo lorem, in feugiat elit ex non ligula. Quisque at vestibulum sapien, nec facilisis
+        neque. Aenean luctus, arcu ut rhoncus luctus, est massa rhoncus mauris, nec luctus urna sem
+        quis massa. Nam elit felis, congue et ligula eget, ultricies tincidunt erat. Vivamus
+        eleifend no dui ac dictum. In nulla justo, pulvinar ut tristique sed, congue et orci.
+
+           Quisque imperdiet mi lectus, ac scelerisque augue posuere ut. Duis non pulvinar ipsum,
+        finibus risus. Donec ullamcorper nisl at sodales lobortis. Mauris neque leo, vestibulum sit
+        amet placerat vel, aliquet vel sapien. Morbi massa tellus, scelerisque quis nisl in, feugiat
+        posuere augue. Aenean congue sem ut ipsum vulputate rhoncus vitae at eros. Maecenas in velit
+        orci pellentesque lobortis ac at felis. Vestibulum odio quam, lacinia dapibus ornare eu,
+        vulputate a eros. Curabitur eleifend ornare tellus, non sollicitudin justo viverra in. Sed
+        sodales neque et lacus semper, in pharetra est consequat. Nunc vehicula volutpat lectus, sit
+        amet scelerisque nisi. Aenean sollicitudin, sem at ultricies efficitur, eros metus
+        nisl, et fringilla felis lacus non orci. Praesent eros libero, finibus in purus id,
+        tempor ipsum. Donec suscipit libero velit. Aliquam quis diam pharetra, cursus ipsum in,
+        gravida metus. Maecenas ultrices ligula a ullamcorper scelerisque.
+
+           Donec tincidunt felis turpis, id venenatis neque convallis in. Proin euismod ligula nec
+        urna vulputate, sed elementum mauris ultrices. Ut efficitur sem vel mi vestibulum placerat.
+        Sed fermentum lacus nec metus dictum, a commodo quam fermentum. Sed vel vulputate magna.
+        Integer convallis nisi sit amet mi lobortis pellentesque. In egestas porttitor elit eu
+        scelerisque. Suspendisse eleifend vel enim quis tincidunt. Sed placerat risus et pretium
+        porttitor. Nam justo mi, cursus eu pellentesque vel, bibendum ut nisl. Nulla condimentum
+        lorem, non sagittis lorem volutpat vitae. Mauris nec libero lorem. Vestibulum lacus ex,
+        vulputate non massa vitae, pellentesque vestibulum dolor.
+
+           Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+        Suspendisse vitae erat nisl. Vestibulum elit ante, semper et semper sit amet, fringilla
+        sapien. Morbi ac nisi sit amet turpis tincidunt mattis ac eget nisl. Nunc a venenatis quam,
+        facilisis maximus odio. Aliquam erat volutpat. Maecenas leo enim, ornare a magna quis,
+        venenatis ornare nulla. Aliquam venenatis nibh et elit tincidunt, ut egestas lorem finibus.
+        Integer iaculis dolor sed enim blandit vestibulum. Nullam vel libero ultricies, sagittis
+        tortor non, molestie eros.</string>
 </resources>
diff --git a/tests/tests/assist/service/AndroidManifest.xml b/tests/tests/assist/service/AndroidManifest.xml
index 5a22d31..354d771 100644
--- a/tests/tests/assist/service/AndroidManifest.xml
+++ b/tests/tests/assist/service/AndroidManifest.xml
@@ -18,6 +18,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.assist.service">
 
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
     <application>
       <uses-library android:name="android.test.runner" />
       <service android:name=".MainInteractionService"
@@ -43,6 +45,10 @@
               <action android:name="android.intent.action.START_TEST_ASSIST_STRUCTURE" />
               <action android:name="android.intent.action.START_TEST_LIFECYCLE" />
               <action android:name="android.intent.action.START_TEST_FLAG_SECURE" />
+              <action android:name="android.intent.action.START_TEST_SCREENSHOT" />
+              <action android:name="android.intent.action.START_TEST_EXTRA_ASSIST" />
+              <action android:name="android.intent.action.START_TEST_TEXTVIEW" />
+              <action android:name="android.intent.action.START_TEST_LARGE_VIEW_HIERARCHY" />
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
       </activity>
diff --git a/tests/tests/assist/service/res/layout/assist_layer.xml b/tests/tests/assist/service/res/layout/assist_layer.xml
index 49f35c9..3677208 100644
--- a/tests/tests/assist/service/res/layout/assist_layer.xml
+++ b/tests/tests/assist/service/res/layout/assist_layer.xml
@@ -1,9 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/assist_layer"
-        android:layout_width="match_parent"
-        android:background="@color/assist_layer_background"
-        android:layout_height="match_parent">
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/assist_layer"
+    android:layout_width="match_parent"
+    android:background="@color/assist_layer_background"
+    android:layout_height="match_parent">
     <TextView
         android:layout_centerInParent="true"
         android:text="@string/test_assistant_text"
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java
index b7d67f1..ddf43bd 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java
@@ -26,11 +26,17 @@
 public class DelayedAssistantActivity extends Activity {
     static final String TAG = "DelayedAssistantActivity";
 
+    @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Intent intent = new Intent();
         intent.setComponent(new ComponentName(this, MainInteractionService.class));
         intent.putExtra(Utils.EXTRA_REGISTER_RECEIVER, true);
+        intent.putExtra(Utils.TESTCASE_TYPE, getIntent().getStringExtra(Utils.TESTCASE_TYPE));
+        intent.putExtra(Utils.DISPLAY_WIDTH_KEY,
+                getIntent().getIntExtra(Utils.DISPLAY_WIDTH_KEY, 0));
+        intent.putExtra(Utils.DISPLAY_HEIGHT_KEY,
+                getIntent().getIntExtra(Utils.DISPLAY_HEIGHT_KEY, 0));
         finish();
         ComponentName serviceName = startService(intent);
         Log.i(TAG, "Started service: " + serviceName);
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
index fc19e1c..916d676 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
@@ -30,11 +30,17 @@
 import android.service.voice.VoiceInteractionSession;
 import android.util.Log;
 
+import java.lang.Exception;
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 public class MainInteractionService extends VoiceInteractionService {
     static final String TAG = "MainInteractionService";
     private Intent mIntent;
     private boolean mReady = false;
-    private BroadcastReceiver mBroadcastReceiver;
+    private BroadcastReceiver mBroadcastReceiver, mResumeReceiver;
+    private CountDownLatch mResumeLatch;
 
     @Override
     public void onReady() {
@@ -57,17 +63,27 @@
         } else {
             if (isActiveService(this, new ComponentName(this, getClass()))) {
                 if (mIntent.getBooleanExtra(Utils.EXTRA_REGISTER_RECEIVER, false)) {
-                    Log.i(TAG, "Registering receiver to start session later");
+                    mResumeLatch = new CountDownLatch(1);
                     if (mBroadcastReceiver == null) {
                         mBroadcastReceiver = new MainInteractionServiceBroadcastReceiver();
-                        registerReceiver(mBroadcastReceiver,
-                                new IntentFilter(Utils.BROADCAST_INTENT_START_ASSIST));
+                        IntentFilter filter = new IntentFilter();
+                        filter.addAction(Utils.BROADCAST_INTENT_START_ASSIST);
+                        registerReceiver(mBroadcastReceiver, filter);
+                        Log.i(TAG, "Registered receiver to start session later");
+
+                        IntentFilter resumeFilter = new IntentFilter(Utils.APP_3P_HASRESUMED);
+                        mResumeReceiver = new MainServiceAppResumeReceiver();
+                        registerReceiver(mResumeReceiver, resumeFilter);
+                        Log.i(TAG, "Registered receiver for resuming activity");
                     }
                     sendBroadcast(new Intent(Utils.ASSIST_RECEIVER_REGISTERED));
               } else {
                   Log.i(TAG, "Yay! about to start session");
-                  showSession(new Bundle(), VoiceInteractionSession.SHOW_WITH_ASSIST |
-                          VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
+                  Bundle bundle = new Bundle();
+                  bundle.putString(Utils.TESTCASE_TYPE,
+                          mIntent.getStringExtra(Utils.TESTCASE_TYPE));
+                  showSession(bundle, VoiceInteractionSession.SHOW_WITH_ASSIST |
+                      VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
               }
             } else {
                 Log.wtf(TAG, "**** Not starting MainInteractionService because" +
@@ -81,7 +97,49 @@
         public void onReceive(Context context, Intent intent) {
             Log.i(MainInteractionService.TAG, "Recieved broadcast to start session now.");
             if (intent.getAction().equals(Utils.BROADCAST_INTENT_START_ASSIST)) {
-                showSession(new Bundle(), SHOW_WITH_ASSIST | SHOW_WITH_SCREENSHOT);
+                String testCaseName = intent.getStringExtra(Utils.TESTCASE_TYPE);
+                Log.i(MainInteractionService.TAG, "trying to start 3p activity: " + testCaseName);
+                Bundle extras = intent.getExtras();
+                if (extras == null) {
+                    extras = new Bundle();
+                }
+                if (testCaseName.equals(Utils.SCREENSHOT)) {
+                    try {
+                        // extra info to pass along to 3p activity.
+
+                        Intent intent3p = new Intent();
+                        Log.i(TAG, "starting the 3p app again");
+                        intent3p.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        intent3p.setAction("android.intent.action.TEST_APP_" + testCaseName);
+                        intent3p.setComponent(Utils.getTestAppComponent(testCaseName));
+                        intent3p.putExtras(extras);
+                        startActivity(intent3p);
+                        if (!MainInteractionService.this.mResumeLatch
+                                .await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                            Log.i(TAG, "waited for 3p activity to resume");
+                        }
+                    } catch (Exception e) {
+                        Log.i(TAG, "failed so reload 3p app: " + e.toString());
+                    }
+                }
+                extras.putString(Utils.TESTCASE_TYPE, mIntent.getStringExtra(Utils.TESTCASE_TYPE));
+                MainInteractionService.this.showSession(
+                        extras, SHOW_WITH_ASSIST | SHOW_WITH_SCREENSHOT);
+            }
+        }
+    }
+
+    private class MainServiceAppResumeReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(Utils.APP_3P_HASRESUMED)) {
+                Log.i(MainInteractionService.TAG,
+                    "3p activity has resumed in this new receiver");
+                if (MainInteractionService.this.mResumeLatch != null) {
+                    MainInteractionService.this.mResumeLatch.countDown();
+                } else {
+                    Log.i(TAG, "mResumeLatch was null");
+                }
             }
         }
     }
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
index 38d03f8..7bca9be 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
@@ -24,15 +24,24 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Bitmap;
+import android.graphics.Color;
+
+import android.graphics.Point;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionSession;
+import android.util.DisplayMetrics;
 import android.util.Log;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.Display;
+import android.view.ViewTreeObserver;
 
 import java.io.ByteArrayOutputStream;
+import java.util.Date;
 
 import android.assist.common.Utils;
+import android.view.WindowManager;
 
 public class MainInteractionSession extends VoiceInteractionSession {
     static final String TAG = "MainInteractionSession";
@@ -43,7 +52,13 @@
 
     private boolean hasReceivedAssistData = false;
     private boolean hasReceivedScreenshot = false;
+    private int mCurColor;
+    private int mDisplayHeight;
+    private int mDisplayWidth;
+    private Bitmap mScreenshot;
     private BroadcastReceiver mReceiver;
+    private String mTestName;
+    private View mContentView;
 
     MainInteractionSession(Context context) {
         super(context);
@@ -78,13 +93,30 @@
 
     @Override
     public void onShow(Bundle args, int showFlags) {
-        // set some content view.
-        // TODO: check that the view takes up the whole screen.
-        // check that interactor mode is for assist
         if ((showFlags & SHOW_WITH_ASSIST) == 0) {
             return;
         }
+        mTestName = args.getString(Utils.TESTCASE_TYPE, "");
+        mCurColor = args.getInt(Utils.SCREENSHOT_COLOR_KEY);
+        mDisplayHeight = args.getInt(Utils.DISPLAY_HEIGHT_KEY);
+        mDisplayWidth = args.getInt(Utils.DISPLAY_WIDTH_KEY);
         super.onShow(args, showFlags);
+        mContentView.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    mContentView.getViewTreeObserver().removeOnPreDrawListener(this);
+                    Display d = mContentView.getDisplay();
+                    Point displayPoint = new Point();
+                    d.getRealSize(displayPoint);
+                    Intent intent = new Intent(Utils.BROADCAST_CONTENT_VIEW_HEIGHT);
+                    intent.putExtra(Utils.EXTRA_CONTENT_VIEW_HEIGHT, mContentView.getHeight());
+                    intent.putExtra(Utils.EXTRA_CONTENT_VIEW_WIDTH, mContentView.getWidth());
+                    intent.putExtra(Utils.EXTRA_DISPLAY_POINT, displayPoint);
+                    mContext.sendBroadcast(intent);
+                    return true;
+                }
+            });
     }
 
     @Override
@@ -107,17 +139,52 @@
     public void onHandleScreenshot(/*@Nullable*/ Bitmap screenshot) {
         Log.i(TAG, String.format("onHandleScreenshot - Screenshot: %s", screenshot));
         super.onHandleScreenshot(screenshot);
-        ByteArrayOutputStream bs = new ByteArrayOutputStream();
+
         if (screenshot != null) {
-            screenshot.compress(Bitmap.CompressFormat.PNG, 50, bs);
-            mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, bs.toByteArray());
+            mAssistData.putBoolean(Utils.ASSIST_SCREENSHOT_KEY, true);
+
+            if (mTestName.equals(Utils.SCREENSHOT)) {
+                boolean screenshotMatches = compareScreenshot(screenshot, mCurColor);
+                Log.i(TAG, "this is a screenshot test. Matches? " + screenshotMatches);
+                mAssistData.putBoolean(
+                    Utils.COMPARE_SCREENSHOT_KEY, screenshotMatches);
+            }
         } else {
-            mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, null);
+            mAssistData.putBoolean(Utils.ASSIST_SCREENSHOT_KEY, false);
         }
         hasReceivedScreenshot = true;
         maybeBroadcastResults();
     }
 
+    private boolean compareScreenshot(Bitmap screenshot, int color) {
+        Point size = new Point(mDisplayWidth, mDisplayHeight);
+
+        if (screenshot.getWidth() != size.x || screenshot.getHeight() != size.y) {
+            Log.i(TAG, "width  or height didn't match: " + size + " vs " + screenshot.getWidth()
+                    + "," + screenshot.getHeight());
+            return false;
+        }
+        int[] pixels = new int[size.x * size.y];
+        screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y);
+
+        int expectedColor = 0;
+        int wrongColor = 0;
+        for (int pixel : pixels) {
+            if (pixel == color) {
+                expectedColor += 1;
+            } else {
+                wrongColor += 1;
+            }
+        }
+
+        double colorRatio = (double) expectedColor / (expectedColor + wrongColor);
+        Log.i(TAG, "the ratio is " + colorRatio);
+        if (colorRatio < 0.6) {
+            return false;
+        }
+        return true;
+    }
+
     private void maybeBroadcastResults() {
         if (!hasReceivedAssistData) {
             Log.i(TAG, "waiting for assist data before broadcasting results");
@@ -141,13 +208,7 @@
         if (f == null) {
             Log.wtf(TAG, "layout inflater was null");
         }
-        return f.inflate(R.layout.assist_layer,null);
-    }
-
-    class DoneReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.i(TAG, "Done_broadcast " + intent.getAction());
-        }
+        mContentView = f.inflate(R.layout.assist_layer,null);
+        return mContentView;
     }
 }
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index 8ff235b..4c1b1f3 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -34,10 +34,12 @@
  */
 
 public class AssistStructureTest extends AssistTestBase {
+    private static final String TAG = "AssistStructureTest";
     private static final String TEST_CASE_TYPE = Utils.ASSIST_STRUCTURE;
 
     private BroadcastReceiver mReceiver;
     private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
 
     public AssistStructureTest() {
         super();
@@ -65,7 +67,7 @@
         }
         mReceiver = new AssistStructureTestBroadcastReceiver();
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Utils.ASSIST_STRUCTURE_HASRESUMED);
+        filter.addAction(Utils.APP_3P_HASRESUMED);
         filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
         mContext.registerReceiver(mReceiver, filter);
     }
@@ -80,7 +82,7 @@
     public void testAssistStructure() throws Exception {
         mTestActivity.start3pApp(TEST_CASE_TYPE);
         mTestActivity.startTest(TEST_CASE_TYPE);
-        waitForAssistantToBeReady();
+        waitForAssistantToBeReady(mReadyLatch);
         waitForOnResume();
         startSession();
         waitForContext();
@@ -94,11 +96,15 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(Utils.ASSIST_STRUCTURE_HASRESUMED)) {
-                mHasResumedLatch.countDown();
+            if (action.equals(Utils.APP_3P_HASRESUMED)) {
+                if (mHasResumedLatch != null) {
+                    mHasResumedLatch.countDown();
+                }
             } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
-                mAssistantReadyLatch.countDown();
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 25460e5..46fb8d9 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -33,31 +33,41 @@
 import android.cts.util.SystemUtil;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.webkit.WebView;
+import android.widget.EditText;
 import android.widget.TextView;
 
+import java.lang.Math;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 public class AssistTestBase extends ActivityInstrumentationTestCase2<TestStartActivity> {
-    static final String TAG = "AssistTestBase";
+    private static final String TAG = "AssistTestBase";
 
     protected TestStartActivity mTestActivity;
     protected AssistContent mAssistContent;
     protected AssistStructure mAssistStructure;
-    protected Bitmap mScreenshot;
+    protected boolean mScreenshot;
+    protected Bitmap mAppScreenshot;
     protected BroadcastReceiver mReceiver;
     protected Bundle mAssistBundle;
     protected Context mContext;
-    protected CountDownLatch mLatch, mAssistantReadyLatch;
-
+    protected CountDownLatch mLatch, mScreenshotLatch, mHasResumedLatch;
+    protected boolean mScreenshotMatches;
+    private Point mDisplaySize;
     private String mTestName;
     private View mView;
 
@@ -68,29 +78,49 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mAssistantReadyLatch = new CountDownLatch(1);
         mContext = getInstrumentation().getTargetContext();
         SystemUtil.runShellCommand(getInstrumentation(),
                 "settings put secure assist_structure_enabled 1");
         SystemUtil.runShellCommand(getInstrumentation(),
                 "settings put secure assist_screenshot_enabled 1");
         logContextAndScreenshotSetting();
+
+        // reset old values
+        mScreenshotMatches = false;
+        mScreenshot = false;
+        mAssistStructure = null;
+        mAssistContent = null;
+        mAssistBundle = null;
+
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new TestResultsReceiver();
+        mContext.registerReceiver(mReceiver,
+            new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
     }
 
     @Override
     protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mReceiver);
         mTestActivity.finish();
-        super.tearDown();
         mContext.sendBroadcast(new Intent(Utils.HIDE_SESSION));
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+        super.tearDown();
     }
 
+    /**
+     * Starts the shim service activity
+     */
     protected void startTestActivity(String testName) {
         Intent intent = new Intent();
         mTestName = testName;
         intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + testName);
         intent.setComponent(new ComponentName(getInstrumentation().getContext(),
                 TestStartActivity.class));
+        intent.putExtra(Utils.TESTCASE_TYPE, testName);
         setActivityIntent(intent);
         mTestActivity = getActivity();
     }
@@ -98,9 +128,9 @@
     /**
      * Called when waiting for Assistant's Broadcast Receiver to be setup
      */
-    public void waitForAssistantToBeReady() throws Exception {
+    public void waitForAssistantToBeReady(CountDownLatch latch) throws Exception {
         Log.i(TAG, "waiting for assistant to be ready before continuing");
-        if (!mAssistantReadyLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+        if (!latch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
             fail("Assistant was not ready before timeout of: " + Utils.TIMEOUT_MS + "msec");
         }
     }
@@ -109,11 +139,33 @@
      * Send broadcast to MainInteractionService to start a session
      */
     protected void startSession() {
-        mContext.sendBroadcast(new Intent(Utils.BROADCAST_INTENT_START_ASSIST));
+        startSession(mTestName, new Bundle());
+    }
+
+    protected void startSession(String testName, Bundle extras) {
+        Intent intent = new Intent(Utils.BROADCAST_INTENT_START_ASSIST);
+        Log.i(TAG, "passed in class test name is: " + testName);
+        intent.putExtra(Utils.TESTCASE_TYPE, testName);
+        addDimensionsToIntent(intent);
+        intent.putExtras(extras);
+        mContext.sendBroadcast(intent);
     }
 
     /**
-     * Called after startTestActivity
+     * Calculate display dimensions (including navbar) to pass along in the given intent.
+     */
+    private void addDimensionsToIntent(Intent intent) {
+        if (mDisplaySize == null) {
+            Display display = mTestActivity.getWindowManager().getDefaultDisplay();
+            mDisplaySize = new Point();
+            display.getRealSize(mDisplaySize);
+        }
+        intent.putExtra(Utils.DISPLAY_WIDTH_KEY, mDisplaySize.x);
+        intent.putExtra(Utils.DISPLAY_HEIGHT_KEY, mDisplaySize.y);
+    }
+
+    /**
+     * Called after startTestActivity. Includes check for receiving context.
      */
     protected boolean waitForBroadcast() throws Exception {
         mTestActivity.start3pApp(mTestName);
@@ -123,15 +175,16 @@
 
     protected boolean waitForContext() throws Exception {
         mLatch = new CountDownLatch(1);
+
         if (mReceiver != null) {
             mContext.unregisterReceiver(mReceiver);
         }
         mReceiver = new TestResultsReceiver();
         mContext.registerReceiver(mReceiver,
-            new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
+                new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
 
-        if (!mLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-            fail("Failed to receive broadcast in " + Utils.TIMEOUT_MS + "msec");
+        if (!mLatch.await(Utils.getAssistDataTimeout(mTestName), TimeUnit.MILLISECONDS)) {
+            fail("Fail to receive broadcast in " + Utils.getAssistDataTimeout(mTestName) + "msec");
         }
         Log.i(TAG, "Received broadcast with all information.");
         return true;
@@ -150,26 +203,43 @@
 
         if ((mAssistContent == null) != isContentNull) {
             fail(String.format("Should %s have been null - AssistContent: %s",
-                    isContentNull? "":"not", mAssistContent));
+                    isContentNull ? "" : "not", mAssistContent));
         }
 
         if ((mAssistStructure == null) != isStructureNull) {
             fail(String.format("Should %s have been null - AssistStructure: %s",
-                isStructureNull ? "" : "not", mAssistStructure));
+                    isStructureNull ? "" : "not", mAssistStructure));
         }
 
         if ((mAssistBundle == null) != isBundleNull) {
             fail(String.format("Should %s have been null - AssistBundle: %s",
-                    isBundleNull? "":"not", mAssistBundle));
+                    isBundleNull ? "" : "not", mAssistBundle));
         }
 
-        if ((mScreenshot == null) != isScreenshotNull) {
+        if (mScreenshot == isScreenshotNull) {
             fail(String.format("Should %s have been null - Screenshot: %s",
-                    isScreenshotNull? "":"not", mScreenshot));
+                    isScreenshotNull ? "":"not", mScreenshot));
         }
     }
 
     /**
+     * Sends a broadcast with the specified scroll positions to the test app.
+     */
+    protected void scrollTestApp(int scrollX, int scrollY, boolean scrollTextView,
+            boolean scrollScrollView) {
+        mTestActivity.scrollText(scrollX, scrollY, scrollTextView, scrollScrollView);
+        Intent intent = null;
+        if (scrollTextView) {
+            intent = new Intent(Utils.SCROLL_TEXTVIEW_ACTION);
+        } else if (scrollScrollView) {
+            intent = new Intent(Utils.SCROLL_SCROLLVIEW_ACTION);
+        }
+        intent.putExtra(Utils.SCROLL_X_POSITION, scrollX);
+        intent.putExtra(Utils.SCROLL_Y_POSITION, scrollY);
+        mContext.sendBroadcast(intent);
+    }
+
+    /**
      * Verifies the view hierarchy of the backgroundApp matches the assist structure.
      *
      * @param backgroundApp ComponentName of app the assistant is invoked upon
@@ -178,7 +248,7 @@
     protected void verifyAssistStructure(ComponentName backgroundApp, boolean isSecureWindow) {
         // Check component name matches
         assertEquals(backgroundApp.flattenToString(),
-            mAssistStructure.getActivityComponent().flattenToString());
+                mAssistStructure.getActivityComponent().flattenToString());
 
         Log.i(TAG, "Traversing down structure for: " + backgroundApp.flattenToString());
         mView = mTestActivity.findViewById(android.R.id.content).getRootView();
@@ -187,7 +257,7 @@
 
     protected void logContextAndScreenshotSetting() {
         Log.i(TAG, "Context is: " + Settings.Secure.getString(
-            mContext.getContentResolver(), "assist_structure_enabled"));
+                mContext.getContentResolver(), "assist_structure_enabled"));
         Log.i(TAG, "Screenshot is: " + Settings.Secure.getString(
                 mContext.getContentResolver(), "assist_screenshot_enabled"));
     }
@@ -240,9 +310,10 @@
                         + ((ViewGroup) parentView).getChildAt(childInt).getClass().getName());
             }
         }
+        String parentViewId = null;
         if (parentView.getId() > 0) {
-            Log.i(TAG, "View ID: "
-                    + mTestActivity.getResources().getResourceEntryName(parentView.getId()));
+            parentViewId = mTestActivity.getResources().getResourceEntryName(parentView.getId());
+            Log.i(TAG, "View ID: " + parentViewId);
         }
 
         Log.i(TAG, "parentNode is of type: " + parentNode.getClassName());
@@ -251,7 +322,9 @@
                     "nodechild" + nodeInt + " is of type: "
                     + parentNode.getChildAt(nodeInt).getClassName());
         }
-            Log.i(TAG, "Node ID: " + parentNode.getIdEntry());
+        Log.i(TAG, "Node ID: " + parentNode.getIdEntry());
+
+        assertEquals("IDs do not match", parentViewId, parentNode.getIdEntry());
 
         int numViewChildren = 0;
         int numNodeChildren = 0;
@@ -260,31 +333,57 @@
         }
         numNodeChildren = parentNode.getChildCount();
 
-        if  (isSecureWindow) {
+        if (isSecureWindow) {
+            assertTrue("ViewNode property isAssistBlocked is false", parentNode.isAssistBlocked());
             assertEquals("Secure window should only traverse root node.", 0, numNodeChildren);
             isSecureWindow = false;
-            return;
+        } else if (parentNode.getClassName().equals("android.webkit.WebView")) {
+            // WebView will also appear to have no children while the node does, traverse node
+            assertTrue("AssistStructure returned a WebView where the view wasn't one",
+                    parentView instanceof WebView);
+
+            boolean textInWebView = false;
+
+            for (int i = numNodeChildren - 1; i >= 0; i--) {
+               textInWebView |= traverseWebViewForText(parentNode.getChildAt(i));
+            }
+            assertTrue("Did not find expected strings inside WebView", textInWebView);
         } else {
             assertEquals("Number of children did not match.", numViewChildren, numNodeChildren);
-        }
 
-        verifyViewProperties(parentView, parentNode);
+            verifyViewProperties(parentView, parentNode);
 
-        if (parentView instanceof ViewGroup) {
-            parentGroup = (ViewGroup) parentView;
+            if (parentView instanceof ViewGroup) {
+                parentGroup = (ViewGroup) parentView;
 
-            // TODO: set a max recursion level
-            for (int i = numNodeChildren - 1; i >= 0; i--) {
-                View childView = parentGroup.getChildAt(i);
-                ViewNode childNode = parentNode.getChildAt(i);
+                // TODO: set a max recursion level
+                for (int i = numNodeChildren - 1; i >= 0; i--) {
+                    View childView = parentGroup.getChildAt(i);
+                    ViewNode childNode = parentNode.getChildAt(i);
 
-                // if isSecureWindow, should not have reached this point.
-                assertFalse(isSecureWindow);
-                traverseViewAndStructure(childView, childNode, isSecureWindow);
+                    // if isSecureWindow, should not have reached this point.
+                    assertFalse(isSecureWindow);
+                    traverseViewAndStructure(childView, childNode, isSecureWindow);
+                }
             }
         }
     }
 
+    /** 
+     * Return true if the expected strings are found in the WebView, else fail.
+     */
+    private boolean traverseWebViewForText(ViewNode parentNode) {
+        boolean textFound = false;
+        if (parentNode.getText() != null 
+                && parentNode.getText().toString().equals(Utils.WEBVIEW_HTML_GREETING)) {
+            return true;
+        }
+        for (int i = parentNode.getChildCount() - 1; i >= 0; i--) {
+            textFound |= traverseWebViewForText(parentNode.getChildAt(i));
+        }
+        return textFound;
+    }
+
     /**
      * Compare view properties of the view hierarchy with that reported in the assist structure.
      */
@@ -304,21 +403,48 @@
             assertNull("View Node should not have an ID.", parentNode.getIdEntry());
         }
 
-        assertEquals("Scroll X does not match.",
-                parentView.getScrollX(), parentNode.getScrollX());
+        Log.i(TAG, "parent text: " + parentNode.getText());
+        if (parentView instanceof TextView) {
+            Log.i(TAG, "view text: " + ((TextView) parentView).getText());
+        }
 
-        assertEquals("Scroll Y does not match.",
-                parentView.getScrollY(), parentNode.getScrollY());
 
-        assertEquals("Heights do not match.", parentView.getHeight(),
-                parentNode.getHeight());
-
+        assertEquals("Scroll X does not match.", parentView.getScrollX(), parentNode.getScrollX());
+        assertEquals("Scroll Y does not match.", parentView.getScrollY(), parentNode.getScrollY());
+        assertEquals("Heights do not match.", parentView.getHeight(), parentNode.getHeight());
         assertEquals("Widths do not match.", parentView.getWidth(), parentNode.getWidth());
 
-        // TODO: handle unicode/i18n
         if (parentView instanceof TextView) {
-            assertEquals("Text in TextView does not match.",
-                    ((TextView) parentView).getText().toString(), parentNode.getText());
+            if (parentView instanceof EditText) {
+                assertEquals("Text selection start does not match",
+                    ((EditText)parentView).getSelectionStart(), parentNode.getTextSelectionStart());
+                assertEquals("Text selection end does not match",
+                        ((EditText)parentView).getSelectionEnd(), parentNode.getTextSelectionEnd());
+            }
+            TextView textView = (TextView) parentView;
+            assertEquals(textView.getTextSize(), parentNode.getTextSize());
+            String viewString = textView.getText().toString();
+            String nodeString = parentNode.getText().toString();
+
+            if (parentNode.getScrollX() == 0 && parentNode.getScrollY() == 0) {
+                Log.i(TAG, "Verifying text within TextView at the beginning");
+                Log.i(TAG, "view string: " + viewString);
+                Log.i(TAG, "node string: " + nodeString);
+                assertTrue("String length is unexpected: original string - " + viewString.length() +
+                                ", string in AssistData - " + nodeString.length(),
+                        viewString.length() >= nodeString.length());
+                assertTrue("Expected a longer string to be shown. expected: "
+                                + Math.min(viewString.length(), 30) + " was: " + nodeString
+                                .length(),
+                        nodeString.length() >= Math.min(viewString.length(), 30));
+                for (int x = 0; x < parentNode.getText().length(); x++) {
+                    assertEquals("Char not equal at index: " + x,
+                            ((TextView) parentView).getText().toString().charAt(x),
+                            parentNode.getText().charAt(x));
+                }
+            } else if (parentNode.getScrollX() == parentView.getWidth()) {
+
+            }
         } else {
             assertNull(parentNode.getText());
         }
@@ -336,17 +462,20 @@
                 AssistTestBase.this.mAssistContent = assistData.getParcelable(
                         Utils.ASSIST_CONTENT_KEY);
 
-                byte[] bitmapArray = assistData.getByteArray(Utils.ASSIST_SCREENSHOT_KEY);
-                if (bitmapArray != null) {
-                    AssistTestBase.this.mScreenshot = BitmapFactory.decodeByteArray(
-                            bitmapArray, 0, bitmapArray.length);
-                } else {
-                    AssistTestBase.this.mScreenshot = null;
-                }
+                AssistTestBase.this.mScreenshot =
+                        assistData.getBoolean(Utils.ASSIST_SCREENSHOT_KEY, false);
+
+                AssistTestBase.this.mScreenshotMatches = assistData.getBoolean(
+                        Utils.COMPARE_SCREENSHOT_KEY, false);
 
                 if (mLatch != null) {
+                    Log.i(AssistTestBase.TAG, "counting down latch. received assist data.");
                     mLatch.countDown();
                 }
+            } else if (intent.getAction().equals(Utils.APP_3P_HASRESUMED)) {
+                if (mHasResumedLatch != null) {
+                    mHasResumedLatch.countDown();
+                }
             }
         }
     }
diff --git a/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
new file mode 100644
index 0000000..557134b
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 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.assist.cts;
+
+import android.assist.cts.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.cts.util.SystemUtil;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Test verifying the Content View of the Assistant */
+public class AssistantContentViewTest extends AssistTestBase {
+    private static final String TAG = "ContentViewTest";
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mContentViewLatch, mReadyLatch;
+    private Intent mIntent;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mContentViewLatch = new CountDownLatch(1);
+        mReadyLatch = new CountDownLatch(1);
+        setUpAndRegisterReceiver();
+        startTestActivity(Utils.VERIFY_CONTENT_VIEW);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new AssistantContentViewReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.BROADCAST_CONTENT_VIEW_HEIGHT);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mReceiver, filter);
+
+    }
+
+    private void waitForContentView() throws Exception {
+        Log.i(TAG, "waiting for the Assistant's Content View  before continuing");
+        if (!mContentViewLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("failed to receive content view in " + Utils.TIMEOUT_MS + "msec");
+        }
+    }
+
+    public void testAssistantContentViewDimens() throws Exception {
+        mTestActivity.startTest(Utils.VERIFY_CONTENT_VIEW);
+        waitForAssistantToBeReady(mReadyLatch);
+        startSession();
+        waitForContentView();
+        int height = mIntent.getIntExtra(Utils.EXTRA_CONTENT_VIEW_HEIGHT, 0);
+        int width = mIntent.getIntExtra(Utils.EXTRA_CONTENT_VIEW_WIDTH, 0);
+        Point displayPoint = (Point) mIntent.getParcelableExtra(Utils.EXTRA_DISPLAY_POINT);
+        assertEquals(displayPoint.y, height);
+        assertEquals(displayPoint.x, width);
+    }
+
+    private class AssistantContentViewReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.BROADCAST_CONTENT_VIEW_HEIGHT)) {
+                mIntent = intent;
+                if (mContentViewLatch != null) {
+                    mContentViewLatch.countDown();
+                }
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index dc28879..5c8aa19 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
 
 import java.lang.Override;
 import java.util.concurrent.CountDownLatch;
@@ -63,6 +64,7 @@
 
     public void testContextAndScreenshotOff() throws Exception {
         // Both settings off
+        Log.i(TAG, "DisableContext: Screenshot OFF, Context OFF");
         SystemUtil.runShellCommand(getInstrumentation(),
             "settings put secure assist_structure_enabled 0");
         SystemUtil.runShellCommand(getInstrumentation(),
@@ -74,6 +76,7 @@
         verifyAssistDataNullness(true, true, true, true);
 
         // Screenshot off, context on
+        Log.i(TAG, "DisableContext: Screenshot OFF, Context ON");
         SystemUtil.runShellCommand(getInstrumentation(),
             "settings put secure assist_structure_enabled 1");
         SystemUtil.runShellCommand(getInstrumentation(),
@@ -85,6 +88,7 @@
         verifyAssistDataNullness(false, false, false, true);
 
         // Context off, screenshot on
+        Log.i(TAG, "DisableContext: Screenshot ON, Context OFF");
         SystemUtil.runShellCommand(getInstrumentation(),
             "settings put secure assist_structure_enabled 0");
         SystemUtil.runShellCommand(getInstrumentation(),
@@ -95,4 +99,4 @@
 
         verifyAssistDataNullness(true, true, true, true);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java b/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java
new file mode 100644
index 0000000..28b2af2
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 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.assist.cts;
+
+import android.assist.common.Utils;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ExtraAssistDataTest extends AssistTestBase {
+    private static final String TAG = "ExtraAssistDataTest";
+    private static final String TEST_CASE_TYPE = Utils.EXTRA_ASSIST;
+
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+    public ExtraAssistDataTest() {
+        super();
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        setUpAndRegisterReceiver();
+        startTestActivity(TEST_CASE_TYPE);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new ExtraAssistDataReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.APP_3P_HASRESUMED);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    public void testAssistContentAndAssistData() throws Exception {
+        mTestActivity.startTest(TEST_CASE_TYPE);
+        waitForAssistantToBeReady(mReadyLatch);
+        mTestActivity.start3pApp(TEST_CASE_TYPE);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        verifyAssistDataNullness(false, false, false, false);
+
+        Log.i(TAG, "assist bundle is: " + Utils.toBundleString(mAssistBundle));
+
+        // tests that the assist content's structured data is the expected
+        assertEquals("AssistContent structured data did not match data in onProvideAssistContent",
+                Utils.getStructuredJSON(), mAssistContent.getStructuredData());
+        // tests the assist data. EXTRA_ASSIST_CONTEXT is what's expected.
+        Bundle extraExpectedBundle = Utils.getExtraAssistBundle();
+        Bundle extraAssistBundle = mAssistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+        for (String key : extraExpectedBundle.keySet()) {
+            assertTrue("Assist bundle does not contain expected extra context key: " + key,
+                    extraAssistBundle.containsKey(key));
+            assertEquals("Extra assist context bundle values do not match for key: " + key,
+                    extraExpectedBundle.get(key), extraAssistBundle.get(key));
+        }
+    }
+
+    private void waitForOnResume() throws Exception {
+        Log.i(TAG, "waiting for onResume() before continuing");
+        if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+        }
+    }
+
+    private class ExtraAssistDataReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.APP_3P_HASRESUMED)) {
+                if (mHasResumedLatch != null) {
+                    mHasResumedLatch.countDown();
+                }
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
index 2e9932e..35f95a4 100644
--- a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
@@ -37,7 +37,7 @@
 
     private BroadcastReceiver mReceiver;
     private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
-
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
     public FlagSecureTest() {
         super();
     }
@@ -78,7 +78,7 @@
 
     public void testSecureActivity() throws Exception {
         mTestActivity.startTest(TEST_CASE_TYPE);
-        waitForAssistantToBeReady();
+        waitForAssistantToBeReady(mReadyLatch);
         mTestActivity.start3pApp(TEST_CASE_TYPE);
         waitForOnResume();
         startSession();
@@ -93,9 +93,13 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (action.equals(Utils.FLAG_SECURE_HASRESUMED)) {
-                mHasResumedLatch.countDown();
+                if (mHasResumedLatch != null) {
+                    mHasResumedLatch.countDown();
+                }
             } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
-                mAssistantReadyLatch.countDown();
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
             }
         }
     }
diff --git a/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
new file mode 100644
index 0000000..f6b90b9
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 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.assist.cts;
+
+import android.assist.cts.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Test that triggering the Assistant causes the underlying Activity to lose focus **/
+
+public class FocusChangeTest extends AssistTestBase {
+    private static final String TAG = "FocusChangeTest";
+    private static final String TEST_CASE_TYPE = Utils.FOCUS_CHANGE;
+
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mHasGainedFocusLatch = new CountDownLatch(1);
+    private CountDownLatch mHasLostFocusLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        setUpAndRegisterReceiver();
+        startTestActivity(TEST_CASE_TYPE);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new FocusChangeTestReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.GAINED_FOCUS);
+        filter.addAction(Utils.LOST_FOCUS);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private void waitToGainFocus() throws Exception {
+        Log.i(TAG, "Waiting for the underlying activity to gain focus before continuing.");
+        if (!mHasGainedFocusLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to gain focus in " + Utils.TIMEOUT_MS + "msec.");
+        }
+    }
+
+    private void waitToLoseFocus() throws Exception {
+        Log.i(TAG, "Waiting for the underlying activity to lose focus.");
+        if (!mHasLostFocusLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity maintained focus despite the Assistant Firing"
+                 + Utils.TIMEOUT_MS + "msec.");
+        }
+    }
+
+    public void testLayerCausesUnderlyingActivityToLoseFocus() throws Exception {
+        mTestActivity.startTest(Utils.FOCUS_CHANGE);
+        waitForAssistantToBeReady(mReadyLatch);
+        mTestActivity.start3pApp(Utils.FOCUS_CHANGE);
+        waitToGainFocus();
+        startSession();
+        waitToLoseFocus();
+    }
+
+    private class FocusChangeTestReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.GAINED_FOCUS) && mHasGainedFocusLatch != null) {
+                mHasGainedFocusLatch.countDown();
+            } else if (action.equals(Utils.LOST_FOCUS) && mHasLostFocusLatch != null) {
+                mHasLostFocusLatch.countDown();
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java b/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java
new file mode 100644
index 0000000..bc2ab80
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 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.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *  Test that the AssistStructure returned is properly formatted.
+ */
+
+public class LargeViewHierarchyTest extends AssistTestBase {
+    private static final String TAG = "LargeViewHierarchyTest";
+    private static final String TEST_CASE_TYPE = Utils.LARGE_VIEW_HIERARCHY;
+
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+    public LargeViewHierarchyTest() {
+        super();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setUpAndRegisterReceiver();
+        startTestActivity(TEST_CASE_TYPE);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new LargeViewTestBroadcastReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.APP_3P_HASRESUMED);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private void waitForOnResume() throws Exception {
+        Log.i(TAG, "waiting for onResume() before continuing");
+        if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+        }
+    }
+
+    public void testTextView() throws Exception {
+        mTestActivity.start3pApp(TEST_CASE_TYPE);
+        mTestActivity.startTest(TEST_CASE_TYPE);
+        waitForAssistantToBeReady(mReadyLatch);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        verifyAssistDataNullness(false, false, false, false);
+
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+                false /*FLAG_SECURE set*/);
+    }
+
+    private class LargeViewTestBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.APP_3P_HASRESUMED) && mHasResumedLatch != null) {
+                mHasResumedLatch.countDown();
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED) && mReadyLatch != null) {
+                mReadyLatch.countDown();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
index 7451017..c886b74 100644
--- a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
+++ b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
@@ -46,15 +46,18 @@
     private static final String action_onStop = Utils.LIFECYCLE_ONSTOP;
     private static final String action_onDestroy = Utils.LIFECYCLE_ONDESTROY;
 
+    private static final String TEST_CASE_TYPE = Utils.LIFECYCLE;
+
     private BroadcastReceiver mLifecycleTestBroadcastReceiver;
     private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
     private CountDownLatch mActivityLifecycleLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         setUpAndRegisterReceiver();
-        startTestActivity(Utils.LIFECYCLE);
+        startTestActivity(TEST_CASE_TYPE);
     }
 
     @Override
@@ -96,7 +99,7 @@
 
     public void testLayerDoesNotTriggerLifecycleMethods() throws Exception {
         mTestActivity.startTest(Utils.LIFECYCLE);
-        waitForAssistantToBeReady();
+        waitForAssistantToBeReady(mReadyLatch);
         mTestActivity.start3pApp(Utils.LIFECYCLE);
         waitForOnResume();
         startSession();
@@ -108,16 +111,18 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(action_hasResumed)) {
+            if (action.equals(action_hasResumed) && mHasResumedLatch != null) {
                 mHasResumedLatch.countDown();
-            } else if (action.equals(action_onPause)) {
+            } else if (action.equals(action_onPause) && mActivityLifecycleLatch != null) {
                 mActivityLifecycleLatch.countDown();
-            } else if (action.equals(action_onStop)) {
+            } else if (action.equals(action_onStop) && mActivityLifecycleLatch != null) {
                 mActivityLifecycleLatch.countDown();
-            } else if (action.equals(action_onDestroy)) {
+            } else if (action.equals(action_onDestroy) && mActivityLifecycleLatch != null) {
                 mActivityLifecycleLatch.countDown();
             } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
-                mAssistantReadyLatch.countDown();
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
             }
         }
     }
diff --git a/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java
new file mode 100644
index 0000000..45082ae
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 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.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.DatabaseUtils;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.util.Log;
+
+import junit.framework.Test;
+
+import java.lang.Exception;
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ScreenshotTest extends AssistTestBase {
+    static final String TAG = "ScreenshotTest";
+
+    private static final String TEST_CASE_TYPE = Utils.SCREENSHOT;
+
+    private BroadcastReceiver mScreenshotActivityReceiver;
+    private CountDownLatch mHasResumedLatch, mReadyLatch;
+
+    public ScreenshotTest() {
+        super();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mReadyLatch = new CountDownLatch(1);
+        // set up receiver
+        mScreenshotActivityReceiver = new ScreenshotTestReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        filter.addAction(Utils.APP_3P_HASRESUMED);
+        mContext.registerReceiver(mScreenshotActivityReceiver, filter);
+
+        // start test start activity
+        startTestActivity(TEST_CASE_TYPE);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mScreenshotActivityReceiver != null) {
+            mContext.unregisterReceiver(mScreenshotActivityReceiver);
+        }
+        super.tearDown();
+    }
+
+    public void testRedScreenshot() throws Exception {
+        Log.i(TAG, "Starting screenshot test");
+        mTestActivity.startTest(TEST_CASE_TYPE);
+        Log.i(TAG, "start waitForAssistantToBeReady()");
+        waitForAssistantToBeReady(mReadyLatch);
+
+        waitForActivityResumeAndAssist(Color.RED);
+        verifyAssistDataNullness(false, false, false, false);
+        assertTrue(mScreenshotMatches);
+    }
+
+    public void testGreenScreenshot() throws Exception {
+        Log.i(TAG, "Starting screenshot test");
+        mTestActivity.startTest(TEST_CASE_TYPE);
+        Log.i(TAG, "start waitForAssistantToBeReady()");
+        waitForAssistantToBeReady(mReadyLatch);
+
+        waitForActivityResumeAndAssist(Color.GREEN);
+        verifyAssistDataNullness(false, false, false, false);
+        assertTrue(mScreenshotMatches);
+    }
+
+    public void testBlueScreenshot() throws Exception {
+        Log.i(TAG, "Starting screenshot test");
+        mTestActivity.startTest(TEST_CASE_TYPE);
+        Log.i(TAG, "start waitForAssistantToBeReady()");
+        waitForAssistantToBeReady(mReadyLatch);
+
+        waitForActivityResumeAndAssist(Color.BLUE);
+        verifyAssistDataNullness(false, false, false, false);
+        assertTrue(mScreenshotMatches);
+    }
+
+    private void waitForActivityResumeAndAssist(int color) throws Exception {
+        mHasResumedLatch = new CountDownLatch(1);
+        Bundle extras = new Bundle();
+        extras.putInt(Utils.SCREENSHOT_COLOR_KEY, color);
+        startSession(TEST_CASE_TYPE, extras);
+        Log.i(TAG, "waiting for onResume() before continuing.");
+        if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+        }
+        waitForContext();
+    }
+
+    private class ScreenshotTestReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.i(ScreenshotTest.TAG, "Got some broadcast: " + action);
+            if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+                Log.i(ScreenshotTest.TAG, "Received assist receiver is registered.");
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
+            } else if (action.equals(Utils.APP_3P_HASRESUMED)) {
+                if (mHasResumedLatch != null) {
+                    mHasResumedLatch.countDown();
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/TestStartActivity.java b/tests/tests/assist/src/android/assist/cts/TestStartActivity.java
index 16c924f..e54e774 100644
--- a/tests/tests/assist/src/android/assist/cts/TestStartActivity.java
+++ b/tests/tests/assist/src/android/assist/cts/TestStartActivity.java
@@ -23,21 +23,62 @@
 import android.app.assist.AssistStructure.ViewNode;
 import android.content.Intent;
 import android.content.ComponentName;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ScrollView;
 import android.widget.TextView;
 
+import java.lang.Override;
+
 public class TestStartActivity extends Activity {
     static final String TAG = "TestStartActivity";
 
+    private ScrollView mScrollView;
+    private TextView mTextView;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Log.i(TAG, " in onCreate");
-        setContentView(R.layout.test_app);
+        // Set the respective view we want compared with the test activity
+        String testName = getIntent().getStringExtra(Utils.TESTCASE_TYPE);
+        switch (testName) {
+            case Utils.ASSIST_STRUCTURE:
+                setContentView(R.layout.test_app);
+                setTitle(R.string.testAppTitle);
+                return;
+            case Utils.TEXTVIEW:
+                setContentView(R.layout.text_view);
+                mTextView =  (TextView) findViewById(R.id.text_view);
+                mScrollView = (ScrollView) findViewById(R.id.scroll_view);
+                setTitle(R.string.textViewActivityTitle);
+                return;
+            case Utils.LARGE_VIEW_HIERARCHY:
+                setContentView(R.layout.multiple_text_views);
+                setTitle(R.string.testAppTitle);
+                return;
+            case Utils.WEBVIEW:
+                if (getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_WEBVIEW)) {
+                    setContentView(R.layout.webview);
+                    setTitle(R.string.webViewActivityTitle);
+                    WebView webview = (WebView) findViewById(R.id.webview);
+                    webview.setWebViewClient(new WebViewClient() {
+                        @Override
+                        public void onPageFinished(WebView view, String url) {
+                            sendBroadcast(new Intent(Utils.TEST_ACTIVITY_LOADED));
+                        }
+                    });
+                    webview.loadData(Utils.WEBVIEW_HTML, "text/html", "UTF-8");
+                }
+                return;
+        }
     }
 
     @Override
@@ -58,17 +99,28 @@
 
     public void start3pApp(String testCaseName) {
         Intent intent = new Intent();
+        intent.putExtra(Utils.TESTCASE_TYPE, testCaseName);
         intent.setAction("android.intent.action.TEST_APP_" + testCaseName);
         intent.setComponent(Utils.getTestAppComponent(testCaseName));
         startActivity(intent);
     }
 
-    @Override protected void onPause() {
+    public void start3pAppWithColor(String testCaseName, int color) {
+        Intent intent = new Intent();
+        intent.setAction("android.intent.action.TEST_APP_" + testCaseName);
+        intent.putExtra(Utils.SCREENSHOT_COLOR_KEY, color);
+        intent.setComponent(Utils.getTestAppComponent(testCaseName));
+        startActivity(intent);
+    }
+
+    @Override
+    protected void onPause() {
         Log.i(TAG, " in onPause");
         super.onPause();
     }
 
-    @Override protected void onStart() {
+    @Override
+    protected void onStart() {
         super.onStart();
         Log.i(TAG, " in onStart");
     }
@@ -78,7 +130,8 @@
         Log.i(TAG, " in onRestart");
     }
 
-    @Override protected void onStop() {
+    @Override
+    protected void onStop() {
         Log.i(TAG, " in onStop");
         super.onStop();
     }
@@ -88,4 +141,25 @@
         Log.i(TAG, " in onDestroy");
         super.onDestroy();
     }
+
+    public void scrollText(int scrollX, int scrollY, boolean scrollTextView,
+            boolean scrollScrollView) {
+        if (scrollTextView) {
+            if (scrollX < 0 || scrollY < 0) {
+                scrollX = mTextView.getWidth();
+                scrollY = mTextView.getLayout().getLineTop(mTextView.getLineCount()) - mTextView.getHeight();
+            }
+            Log.i(TAG, "Scrolling text view to " + scrollX + ", " + scrollY);
+            mTextView.scrollTo(scrollX, scrollY);
+        } else if (scrollScrollView) {
+            if (scrollX < 0 || scrollY < 0) {
+                Log.i(TAG, "Scrolling scroll view to bottom right");
+                mScrollView.fullScroll(View.FOCUS_DOWN);
+                mScrollView.fullScroll(View.FOCUS_RIGHT);
+            } else {
+                Log.i(TAG, "Scrolling scroll view to " + scrollX + ", " + scrollY);
+                mScrollView.scrollTo(scrollX, scrollY);
+            }
+        }
+    }
 }
diff --git a/tests/tests/assist/src/android/assist/cts/TextViewTest.java b/tests/tests/assist/src/android/assist/cts/TextViewTest.java
new file mode 100644
index 0000000..e4390bc
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/TextViewTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 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.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *  Test that the AssistStructure returned is properly formatted.
+ */
+
+public class TextViewTest extends AssistTestBase {
+    private static final String TAG = "TextViewTest";
+    private static final String TEST_CASE_TYPE = Utils.TEXTVIEW;
+
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+    public TextViewTest() {
+        super();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setUpAndRegisterReceiver();
+        startTestActivity(TEST_CASE_TYPE);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new TextViewTestBroadcastReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.APP_3P_HASRESUMED);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private void waitForOnResume() throws Exception {
+        Log.i(TAG, "waiting for onResume() before continuing");
+        if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+        }
+    }
+
+    public void testTextView() throws Exception {
+        mTestActivity.start3pApp(TEST_CASE_TYPE);
+        scrollTestApp(0, 0, true, false);
+
+        // Verify that the text view contains the right text
+        mTestActivity.startTest(TEST_CASE_TYPE);
+        waitForAssistantToBeReady(mReadyLatch);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        verifyAssistDataNullness(false, false, false, false);
+
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+                false /*FLAG_SECURE set*/);
+
+        // Verify that the scroll position of the text view is accurate after scrolling.
+        scrollTestApp(10, 50, true /* scrollTextView */, false /* scrollScrollView */);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+
+        scrollTestApp(-1, -1, true, false);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+
+        scrollTestApp(0, 0, true, true);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+
+        scrollTestApp(10, 50, false, true);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+    }
+
+    private class TextViewTestBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.APP_3P_HASRESUMED) && mHasResumedLatch != null) {
+                mHasResumedLatch.countDown();
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED) &&  mReadyLatch != null) {
+                mReadyLatch.countDown();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/WebViewTest.java b/tests/tests/assist/src/android/assist/cts/WebViewTest.java
new file mode 100644
index 0000000..e367e22
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/WebViewTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 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.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *  Test that the AssistStructure returned is properly formatted.
+ */
+
+public class WebViewTest extends AssistTestBase {
+    private static final String TAG = "WebViewTest";
+    private static final String TEST_CASE_TYPE = Utils.WEBVIEW;
+
+    private boolean mWebViewSupported;
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+    private CountDownLatch mTestWebViewLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+    public WebViewTest() {
+        super();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setUpAndRegisterReceiver();
+        startTestActivity(TEST_CASE_TYPE);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new WebViewTestBroadcastReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.APP_3P_HASRESUMED);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        filter.addAction(Utils.TEST_ACTIVITY_LOADED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private void waitForOnResume() throws Exception {
+        Log.i(TAG, "waiting for onResume() before continuing");
+        if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+        }
+    }
+
+    private void waitForTestActivity() throws Exception {
+        Log.i(TAG, "waiting for webview in test activity to load");
+        if (!mTestWebViewLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            // wait for webView to load completely.
+        }
+    }
+
+    public void testWebView() throws Exception {
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+            return;
+        }
+        mTestActivity.start3pApp(TEST_CASE_TYPE);
+        mTestActivity.startTest(TEST_CASE_TYPE);
+        waitForAssistantToBeReady(mReadyLatch);
+        waitForOnResume();
+        waitForTestActivity();
+        startSession();
+        waitForContext();
+        verifyAssistDataNullness(false, false, false, false);
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+                false /*FLAG_SECURE set*/);
+    }
+
+    private class WebViewTestBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.APP_3P_HASRESUMED) && mHasResumedLatch != null) {
+                mHasResumedLatch.countDown();
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED) && mReadyLatch != null) {
+                mReadyLatch.countDown();
+            } else if (action.equals(Utils.TEST_ACTIVITY_LOADED) && mTestWebViewLatch != null) {
+                mTestWebViewLatch.countDown();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/AndroidManifest.xml b/tests/tests/assist/testapp/AndroidManifest.xml
index f14cf22..fa08f55 100644
--- a/tests/tests/assist/testapp/AndroidManifest.xml
+++ b/tests/tests/assist/testapp/AndroidManifest.xml
@@ -18,41 +18,79 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.assist.testapp">
 
+    <uses-permission android:name="android.permission.INTERNET" />
+
     <application>
         <uses-library android:name="android.test.runner" />
 
-        <activity android:name="TestApp"
-                android:label="Assist Structure Test App"
-                android:theme="@android:style/Theme.Material.Light">
+        <activity android:name=".TestApp"
+                android:label="Assist Structure Test Activity">
           <intent-filter>
               <action android:name="android.intent.action.TEST_APP_ASSIST_STRUCTURE" />
+              <action android:name="android.intent.action.TEST_APP_LARGE_VIEWHIERARCHY" />
               <category android:name="android.intent.category.DEFAULT" />
               <category android:name="android.intent.category.VOICE" />
           </intent-filter>
         </activity>
-        <activity android:name="DisableContextActivity"
-            android:label="Disable Context Test Activity"
-            android:theme="@android:style/Theme.Material.Light">
+        <activity android:name=".DisableContextActivity"
+            android:label="Disable Context Test Activity">
             <intent-filter>
                 <action android:name="android.intent.action.TEST_APP_DISABLE_CONTEXT" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
-        <activity android:name="SecureActivity"
-                  android:label="Secure Test Activity"
-                  android:theme="@android:style/Theme.Material.Light">
+        <activity android:name=".SecureActivity"
+                  android:label="Secure Test Activity">
             <intent-filter>
                 <action android:name="android.intent.action.TEST_APP_FLAG_SECURE" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.VOICE" />
             </intent-filter>
         </activity>
-        <activity android:name="LifecycleActivity"
-                  android:label="Life Cycle Check Activity"
-                  android:theme="@android:style/Theme.Material.Light">
+        <activity android:name=".LifecycleActivity"
+                  android:label="Life Cycle Check Activity">
             <intent-filter>
                 <action android:name="android.intent.action.TEST_APP_LIFECYCLE" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.VOICE" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".ScreenshotActivity"
+                  android:label="Screenshot Test Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_SCREENSHOT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.VOICE" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".ExtraAssistDataActivity"
+            android:label="Extra Assist Test Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_EXTRA_ASSIST" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.VOICE" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".TextViewActivity"
+            android:label="TextView Test Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_TEXTVIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".WebViewActivity"
+            android:label="WebView Test Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_WEBVIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".FocusChangeActivity"
+            android:label="Focus Change Test Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_FOCUS_CHANGE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.VOICE" />
             </intent-filter>
         </activity>
     </application>
diff --git a/tests/tests/assist/testapp/res/layout/multiple_text_views.xml b/tests/tests/assist/testapp/res/layout/multiple_text_views.xml
new file mode 100644
index 0000000..455d5e3
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/multiple_text_views.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:orientation="vertical">
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:scrollbars="vertical"
+    android:text="@string/text_too_large_to_fit" />
+
+  <ScrollView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1">
+    <TextView
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:scrollbars="vertical"
+      android:text="@string/text_too_large_to_fit" />
+  </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/layout/screenshot_activity.xml b/tests/tests/assist/testapp/res/layout/screenshot_activity.xml
new file mode 100644
index 0000000..05051dc
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/screenshot_activity.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/screenshot_activity"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/layout/text_view.xml b/tests/tests/assist/testapp/res/layout/text_view.xml
new file mode 100644
index 0000000..0f0f427
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/text_view.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <TextView
+        android:id="@+id/text_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:focusable="false"
+        android:focusableInTouchMode="false"
+        android:scrollbars="vertical"
+        android:clickable="true"
+        android:text="@string/text_too_large_to_fit" />
+
+    <ScrollView
+        android:id="@+id/scroll_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:scrollbars="vertical"
+            android:text="@string/text_too_large_to_fit" />
+    </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/layout/webview.xml b/tests/tests/assist/testapp/res/layout/webview.xml
new file mode 100644
index 0000000..bdb8082
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/webview.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <WebView
+        android:id="@+id/webview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    </WebView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/values/strings.xml b/tests/tests/assist/testapp/res/values/strings.xml
index ae4f16e..670024b 100644
--- a/tests/tests/assist/testapp/res/values/strings.xml
+++ b/tests/tests/assist/testapp/res/values/strings.xml
@@ -14,5 +14,271 @@
      limitations under the License.
 -->
 <resources>
+
+    <string name="app_name">Memegen</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="action_settings">Settings</string>
     <string name="welcome">Hello there!</string>
+    <string name="text_too_large_to_fit">❤ ☀ ☆ ☂ ☻ ♞ ☯ ☭ ☢ € →Hello هتاف للترحيب שלום
+        përshëndetje Добры дзень 您好 হ্যালো здравей მიესალმები Χαίρετε હેલો नमस्ते Nnọọ こんにちは ಹಲೋ
+        Сәлеметсіз бе ជំរាបសួរ 안녕하세요 ສະບາຍດີ ഹലോ हॅलो Сайн байна уу नमस्ते سلامהעלא ہیلو
+        မင်္ဂလာပါ ਸਤ ਸ੍ਰੀ ਅਕਾਲ Здравствуйте здраво ආයුබෝවන් ஹலோ హలో สวัสดี Pẹlẹ o
+        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+        convallis nunc et vestibulum. Sed et consequat quam, blandit varius tortor. Curabitur
+        accumsan nulla lectus, placerat condimentum odio elementum vel. Nulla erat ex, accumsan ut
+        enim sagittis, scelerisque efficitur ante. Nullam quis orci nec magna maximus malesuada ac
+        id sem. Nam sagittis erat risus, a accumsan neque congue sit amet. Nullam risus velit,
+        faucibus eget scelerisque et, maximus eget arcu. Sed porta sed libero ac imperdiet.
+
+        Nulla sem lectus, ullamcorper id dui vel, rutrum interdum augue. Proin aliquam nisi vitae
+        hendrerit tempor. Mauris porttitor velit et egestas feugiat. Vivamus eu dapibus libero,
+        quis fringilla urna. Suspendisse non turpis dui. Vivamus facilisis diam vitae est auctor
+        luctus. Etiam quis lectus viverra, interdum turpis eu, aliquam sem. Nulla vulputate lacinia
+        nisi a dictum. Cras faucibus vitae tortor at ullamcorper. Quisque sit amet sapien maximus,
+        ornare nisi non, imperdiet magna. Vestibulum tempor metus ac mi ultrices dapibus.
+
+        Suspendisse potenti. Mauris pellentesque lacinia tristique. Pellentesque vel dui quis sem
+        lacinia imperdiet feugiat vitae sem. Proin a arcu magna. Sed quis augue eu mi accumsan
+        pellentesque pretium in leo. Duis euismod purus mauris, ac tempor erat auctor non. Quisque
+        bibendum est pulvinar ex dapibus, ac tincidunt nibh tempus. Mauris sodales sem id purus
+        commodo iaculis. Pellentesque a quam dapibus, vehicula lectus at, tincidunt arcu. In
+        placerat porttitor urna quis consequat. Nullam feugiat nisl sed urna hendrerit, sed
+        elementum massa iaculis. Fusce sit amet turpis hendrerit, varius lorem sed, luctus mi.
+        Phasellus sit amet ex orci. Duis scelerisque nisl quis efficitur maximus. Curabitur vitae
+        accumsan nunc, eget varius nisi.
+
+        Fusce efficitur malesuada luctus. Aliquam dapibus tortor sit amet purus semper, sit amet
+        pretium lorem feugiat. Maecenas gravida sed arcu et placerat. Nulla facilisi. Cras placerat
+        rutrum mi, in rutrum mauris maximus at. Mauris eu suscipit ante. Nullam pharetra egestas
+        diam a viverra. Donec sem turpis, tempor malesuada est vel, blandit accumsan magna. In
+        iaculis velit in efficitur hendrerit. Nulla facilisi. Curabitur eget ligula lorem. Sed sit
+        amet dolor ut ligula malesuada condimentum. Phasellus molestie augue eget libero commodo,
+        vel blandit ex blandit.
+
+        Morbi cursus tortor ante, et tempus nisi tempus et. Suspendisse quis gravida diam. Aliquam
+        efficitur dolor sit amet sollicitudin varius. Etiam libero purus, ornare nec nulla vel,
+        ullamcorper blandit nisl. Sed vel consequat diam, id placerat sem. Donec quis elementum
+        urna. In posuere bibendum nunc, in condimentum justo blandit ac. Quisque enim lorem,
+        gravida at purus at, sollicitudin imperdiet erat. Ut consectetur rutrum ante, et pretium
+        odio iaculis a. Nullam a nibh vulputate, volutpat lectus eu, pellentesque felis. Nam
+        vehicula suscipit diam nec convallis. Quisque congue maximus sem, sit amet hendrerit leo
+        tempor et.
+
+        Nam eu consequat dui. Sed semper dignissim mattis. Integer tortor eros, tempor in lectus a,
+        lobortis aliquam dolor. Phasellus at sagittis magna. Nulla eleifend orci ac urna auctor,
+        sit amet luctus urna vulputate. Nulla venenatis venenatis erat ac finibus. Etiam
+        ullamcorper elementum suscipit. Morbi nec velit non mauris porta finibus. Nullam in
+        sagittis odio. Praesent eget nisl ut mauris vestibulum feugiat. Sed vulputate at elit et
+        cursus. Praesent viverra erat blandit nunc egestas, vel feugiat ex condimentum. Class
+        aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+
+        Nulla fermentum mattis urna, non gravida eros vestibulum et. Fusce porttitor augue turpis,
+        sit amet aliquam augue sodales non. Nunc neque odio, sagittis sed gravida euismod, commodo
+        at libero. Donec porttitor pulvinar neque vitae lobortis. Aliquam accumsan velit nec sapien
+        placerat egestas. Aliquam at tincidunt massa, et dignissim justo. Donec sapien ante, rutrum
+        et tristique a, commodo a massa.
+
+        Nunc placerat lobortis magna, et molestie lacus semper porta. Lorem ipsum dolor sit amet,
+        consectetur adipiscing elit. Phasellus ac ligula dui. Duis ultrices viverra eros fermentum
+        finibus. Integer ultrices, felis in accumsan volutpat, mi ligula hendrerit nunc, nec
+        accumsan mauris tellus sit amet metus. Ut pharetra enim et sapien sollicitudin, nec
+        ultricies urna pharetra. Morbi non tortor nec dui feugiat rutrum. Aliquam malesuada sodales
+        risus, sed congue nunc accumsan vitae. Etiam nunc magna, tempus non suscipit eu, feugiat ut
+        nibh. Maecenas et libero ut nisl pellentesque tempor nec vel quam. Etiam sem ligula,
+        ullamcorper non dolor a, viverra placerat nulla. Nullam dictum commodo dui, sed ultrices
+        enim sagittis eget. Morbi non consectetur lectus. In gravida, augue vitae pulvinar
+        molestie, ligula orci vulputate ex, at bibendum urna felis nec nibh. Sed nisl nunc, iaculis
+        at augue venenatis, fringilla accumsan velit. Curabitur nec augue porttitor, rutrum nisi
+        vitae, elementum orci.
+
+        Vestibulum eu tortor iaculis, dignissim velit quis, rhoncus dolor. Donec et tincidunt
+        nulla. Duis faucibus auctor erat ac ultricies. In a fermentum mi. Fusce vitae mi id sem
+        interdum tincidunt. Nulla hendrerit orci turpis, in maximus elit mollis eget. Aliquam erat
+        volutpat. Phasellus mattis est nibh, ut scelerisque ligula egestas eu. Ut molestie orci a
+        malesuada tempor. Sed tempus arcu id orci gravida faucibus. Vivamus ac lacinia neque, at
+        vehicula magna.
+
+        Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+        Nullam aliquam, justo scelerisque egestas sodales, purus odio posuere arcu, ac ultrices
+        nunc felis non massa. Aliquam vulputate ipsum sed aliquet auctor. In pulvinar, eros sit
+        amet ultricies tristique, lacus ipsum scelerisque eros, nec vestibulum est lectus quis
+        lorem. Pellentesque ac augue ut eros mattis viverra vitae ut lacus. Phasellus imperdiet
+        efficitur elit eget tincidunt. Donec sodales metus at dolor pulvinar, at gravida nibh
+        facilisis. Sed nec tellus luctus, cursus lacus sed, euismod orci. Maecenas sit amet leo
+        orci. Nulla non leo non mi eleifend consequat sit amet vitae dui. Sed gravida gravida
+        justo, tincidunt ultrices justo semper vitae. Fusce at nisi nisl. Morbi molestie quis justo
+        a convallis. Curabitur massa lacus, feugiat quis mauris ac, malesuada viverra est.
+
+        Phasellus bibendum faucibus velit, ac scelerisque velit tincidunt eu. Curabitur quis
+        suscipit erat, ac feugiat odio. Nullam et sapien et nibh maximus posuere. Vivamus faucibus
+        justo eget dictum sollicitudin. Etiam at leo eget elit facilisis lobortis. Maecenas
+        bibendum tortor non erat pretium dignissim. Fusce id imperdiet augue. Suspendisse dignissim
+        magna vel odio viverra varius. Maecenas suscipit ante et lorem sodales vehicula. Quisque
+        vel magna id sem suscipit iaculis. Etiam in elementum risus.
+
+        Suspendisse odio nisi, pharetra et purus sit amet, placerat lobortis diam. Phasellus enim
+        nunc, posuere sed porta in, ornare eu ipsum. Phasellus imperdiet porta neque, vitae dapibus
+        tellus feugiat eget. Nulla sodales leo ac efficitur luctus. Vivamus eget ipsum quis ante
+        pulvinar blandit. Vestibulum a justo convallis justo elementum viverra ut sit amet nisl.
+        Suspendisse eget augue fermentum, sagittis risus a, rhoncus elit. Vestibulum in maximus
+        tortor, non vestibulum libero. Nunc accumsan neque a nisl dapibus, id laoreet neque congue.
+        Pellentesque sapien odio, fringilla non nulla nec, varius placerat diam. Aliquam
+        consectetur neque eu ipsum posuere, nec dignissim sem faucibus. Donec sit amet tempor
+        sapien. Nam at libero vel lorem dapibus ultrices a vel augue. Nunc facilisis justo ante,
+        mollis tristique velit aliquet quis. Mauris consectetur odio at urna bibendum aliquam.
+
+           Nullam lectus orci, hendrerit ut ultrices in, dapibus pellentesque nibh. Aliquam arcu
+        metus, lobortis vel dignissim id, tempus ut ante. Integer vitae ante augue. In hac habitasse
+        platea dictumst. Vestibulum in tellus ante. Cras nisi tellus, congue ac velit quis, rhoncus
+        ornare ligula. Sed facilisis gravida pellentesque. Praesent id ultrices orci, ac ultricies
+        arcu. Donec at ante quis augue faucibus congue. Donec mattis quam dui, ut vestibulum orci
+        tempor mattis. Phasellus in quam id tortor varius ullamcorper ac ac ante. Proin cursus
+        accumsan sem, vel finibus lectus eleifend ut. Donec efficitur feugiat diam id ultricies. In
+        quis euismod nisi. Vestibulum eget viverra sapien. Donec scelerisque nec elit vel viverra.
+
+           Sed mi urna, rutrum quis augue vel, aliquet placerat diam. Proin faucibus in odio et
+        consequat. Proin ut ex in mauris eleifend efficitur. Praesent ullamcorper sollicitudin urna,
+        sed mollis elit hendrerit non. Duis leo lorem, efficitur eu auctor sit amet, scelerisque
+        scelerisque magna. Mauris eget massa auctor, viverra arcu a, elementum nibh. Sed
+        pellentesque, nulla sed condimentum posuere, tortor metus congue sem, nec placerat neque
+        magna vitae purus.
+
+           Etiam at risus vitae sapien aliquam condimentum. Vestibulum id libero placerat purus
+        vehicula consectetur. Pellentesque sapien sapien, posuere at pulvinar at, ultrices sed est.
+        Maecenas nec condimentum ante. Aenean volutpat, ex condimentum hendrerit hendrerit, quam
+        nisl  pharetra nibh, vitae bibendum nisl odio vel lacus. Morbi mi tellus, bibendum id mauris
+        eu,  facilisis volutpat turpis. Maecenas rutrum convallis felis. Quisque eget feugiat felis.
+        Duis pellentesque iaculis massa ut facilisis. Donec nec commodo magna. Integer aliquet orci
+        a odio eleifend elementum. Quisque molestie, urna ut molestie eleifend, odio neque maximus
+        enim, eget viverra metus lectus eget quam. Fusce nec urna ac neque bibendum aliquam vel quis
+        dui. Fusce ac quam consequat, feugiat leo vitae, auctor felis.
+
+           Sed ac metus mauris. Sed sed velit ut tortor aliquam vestibulum at eu arcu. Etiam eu
+        posuere lacus. Maecenas id lacus quis sem mollis sodales. Quisque justo sapien, vulputate ac
+        mi ut, congue vestibulum orci. Donec euismod erat rutrum, laoreet urna sed, accumsan purus.
+        Donec eu quam a sapien condimentum accumsan. Sed at tellus lorem. Curabitur bibendum, arcu
+        sit amet finibus sodales, mi sem finibus sem, eget scelerisque tellus neque vel urna.
+        Suspendisse eu augue nec erat suscipit luctus sed non metus.
+
+           Suspendisse porttitor ex ipsum. Pellentesque tristique eros sed pharetra porttitor.
+        Quisque ut elit vehicula, aliquet est nec, faucibus tellus. Donec ex augue, congue eu
+        dignissim  maximus, vestibulum at purus. Nulla quam enim, laoreet sit amet molestie vel,
+        dapibus nec tortor. Sed interdum massa ac orci gravida, vel viverra lacus lacinia. Donec
+        nisl lacus, fermentum at faucibus ac, consequat ut nibh. Praesent laoreet est augue, vitae
+        maximus dui efficitur sit amet. Cras ipsum tellus, tincidunt at volutpat non, tincidunt ut
+        elit. Morbi commodo sagittis gravida. Pellentesque sed ante massa. Phasellus a turpis non
+        turpis cursus consequat sed nec tortor. Proin et augue elit.
+
+           Duis finibus sem commodo rutrum pulvinar. In sollicitudin ante magna, vel facilisis
+        tellus fringilla vel. Nam purus ex, tincidunt eget varius at, euismod nec elit. Curabitur
+        consequat nulla vel nisi iaculis, ut mattis odio congue. Nulla et mollis tortor, a maximus
+        justo. Donec semper eros sed nunc rhoncus condimentum. Donec nibh purus, interdum non lectus
+        id, porta convallis eros.
+
+           Sed hendrerit, dui non sagittis sollicitudin, enim ex imperdiet sapien, et maximus lorem
+        dolor a enim. Nulla risus nisl, vestibulum at ornare posuere, congue in felis. Duis sagittis
+        id diam a varius. Donec viverra eu orci sodales commodo. Cras metus tortor, sodales vitae
+        auctor non, scelerisque a ante. Quisque sodales nisi libero, ut lobortis enim suscipit ut.
+        Cras mi ipsum, maximus non bibendum sit amet, pharetra quis ipsum. Vestibulum venenatis, odi
+        at hendrerit pretium, tellus diam auctor justo, non posuere quam mauris id nisl. Nam dolor
+        nibh, molestie et lectus et, scelerisque porta elit. Vestibulum viverra condimentum auctor.
+        In eros tortor, convallis sed quam eu, ultrices malesuada purus. Integer lorem quam,
+        ultricies at est consectetur, sagittis porttitor eros. Proin non risus vitae lacus
+        consectetur malesuada non pulvinar justo. Aliquam mollis nisi nunc, sit amet vulputate metus
+        sollicitudin vel.
+
+           Quisque auctor varius fermentum. Praesent mollis justo sit amet est consectetur, in
+        volutpat tellus mollis. Aenean at bibendum eros, at finibus nibh. Phasellus nec mi sem.
+        Mauris pellentesque dui sit amet lobortis aliquam. Ut nec massa at urna aliquam gravida vel
+        in magna. Donec consectetur sapien magna, a auctor sapien placerat eu.
+
+           Pellentesque aliquet ante sed lacus gravida rutrum. Maecenas euismod varius felis, nec
+        tempus metus tempus et. Nam convallis augue a massa scelerisque, vel pharetra dolor
+        scelerisque. Fusce porttitor mi a magna rutrum condimentum. Aliquam fermentum at turpis at
+        auctor. Nulla ut suscipit dui. Donec rutrum viverra aliquam. Donec elementum nisl sapien, ac
+        blandit risus porta facilisis. Proin tellus dolor, ornare vel magna sit amet, maximus
+        volutpat felis. Aenean euismod aliquet purus, at finibus nunc elementum eu. Ut faucibus
+        ullamcorper consectetur. Aenean egestas arcu id mauris elementum, at sollicitudin est
+        congue. Sed a odio mattis, sollicitudin erat ut, tristique dolor. Aliquam luctus risus quis
+        tellus semper, a vestibulum nulla viverra.
+
+           Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
+        himenaeos. Vestibulum sit amet nisi felis. Praesent condimentum consequat lacus pulvinar
+        imperdiet. Praesent vel condimentum quam. Maecenas eu aliquet odio. Vestibulum sed nulla
+        mattis lacus porta bibendum a ac eros. Nunc porttitor sagittis laoreet. Duis porta eros at
+        congue tristique. Pellentesque quis fringilla neque, a hendrerit tellus. Pellentesque ac
+        nibh ac tellus pulvinar porttitor et in est. Integer blandit lorem libero, eu pulvinar
+        tellus posuere eget. Vivamus pretium nulla ligula, ut dapibus massa fringilla in.
+        Suspendisse consectetur sem non elit porta, id pellentesque erat dapibus. Quisque ex mi,
+        tempus et hendrerit nec, gravida quis odio. Ut at mi in leo scelerisque venenatis.
+
+           Ut sed tellus in risus tincidunt tempor ut at arcu. Maecenas ut convallis justo. In
+        rutrum urna eu massa rhoncus, eget condimentum augue vehicula. Nullam eget placerat erat.
+        Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+        Aenean at volutpat orci, a lobortis dolor. Sed consequat facilisis interdum. Fusce libero
+        neque, fringilla in congue a, vehicula rutrum ipsum. Nam ornare placerat vestibulum. Proin
+        nec orci velit. Pellentesque scelerisque gravida diam, ut tristique libero tempus eu. Nam
+        semper lacus nec nulla volutpat imperdiet non eget tortor. Sed et pellentesque ligula.
+
+           Aenean a dolor dolor. Curabitur ut placerat lacus, sit amet aliquet orci. Aliquam erat
+        volutpat. Cras mollis sit amet lectus ornare pretium. Vestibulum fringilla orci vel est
+        iaculis, at mattis quam condimentum. Vivamus semper elit consectetur lectus gravida, in
+        sollicitudin mi fringilla. Donec eget lorem in orci blandit aliquam. Pellentesque libero
+        tellus, dignissim id augue et, vulputate viverra nisl. Cum sociis natoque penatibus et
+        magnis dis parturient montes, nascetur ridiculus mus. Donec ac vulputate metus, eu suscipit
+        sem. Donec placerat, nulla at sodales hendrerit, orci tortor vestibulum purus, non pharetra
+        nulla purus posuere arcu.
+
+           Quisque feugiat elit sem, ac interdum diam pharetra nec. Curabitur sem libero, vulputate
+        eu libero vitae, volutpat facilisis ligula. Aenean maximus erat laoreet, interdum ante in,
+        ultrices nisi. Nullam nec efficitur sapien. Integer feugiat et tortor ac bibendum. Donec a
+        scelerisque tortor. Cras quis viverra diam, vitae viverra ipsum. Aliquam ultrices neque sem,
+        congue sodales elit tempus sit amet. Pellentesque habitant morbi tristique senectus et netus
+        et malesuada fames ac turpis egestas. Sed dignissim ipsum eget diam rhoncus, ut finibus
+        nulla pretium. Morbi suscipit nibh vel nisl posuere molestie. Maecenas posuere turpis et
+        rutrum consectetur. Morbi venenatis arcu non gravida vulputate. Vivamus auctor tellus
+        ullamcorper ligula vestibulum cursus. Nunc gravida sit amet nisl quis facilisis.
+
+           Praesent ut justo vestibulum, accumsan mi et, feugiat purus. Nullam pulvinar iaculis
+        pharetra. Aliquam pulvinar risus sit amet elit suscipit tincidunt. In hac habitasse platea
+        dictumst. Etiam eget velit ac magna lacinia efficitur. Vestibulum ante ipsum primis in
+        faucibus orci luctus et ultrices posuere cubilia Curae; Cras volutpat tempus sollicitudin.
+        Ut et ante elit.
+
+           Sed ac tortor justo. Fusce sed metus libero. Duis sagittis tortor ac ante sollicitudin,
+        nec efficitur nibh euismod. Donec porttitor cursus quam, in aliquam lorem feugiat ut.
+        Aliquam tempor lacus eu feugiat feugiat. Nunc pulvinar, libero at auctor commodo, metus diam
+        commodo lorem, in feugiat elit ex non ligula. Quisque at vestibulum sapien, nec facilisis
+        neque. Aenean luctus, arcu ut rhoncus luctus, est massa rhoncus mauris, nec luctus urna sem
+        quis massa. Nam elit felis, congue et ligula eget, ultricies tincidunt erat. Vivamus
+        eleifend no dui ac dictum. In nulla justo, pulvinar ut tristique sed, congue et orci.
+
+           Quisque imperdiet mi lectus, ac scelerisque augue posuere ut. Duis non pulvinar ipsum,
+        finibus risus. Donec ullamcorper nisl at sodales lobortis. Mauris neque leo, vestibulum sit
+        amet placerat vel, aliquet vel sapien. Morbi massa tellus, scelerisque quis nisl in, feugiat
+        posuere augue. Aenean congue sem ut ipsum vulputate rhoncus vitae at eros. Maecenas in velit
+        orci pellentesque lobortis ac at felis. Vestibulum odio quam, lacinia dapibus ornare eu,
+        vulputate a eros. Curabitur eleifend ornare tellus, non sollicitudin justo viverra in. Sed
+        sodales neque et lacus semper, in pharetra est consequat. Nunc vehicula volutpat lectus, sit
+        amet scelerisque nisi. Aenean sollicitudin, sem at ultricies efficitur, eros metus
+        nisl, et fringilla felis lacus non orci. Praesent eros libero, finibus in purus id,
+        tempor ipsum. Donec suscipit libero velit. Aliquam quis diam pharetra, cursus ipsum in,
+        gravida metus. Maecenas ultrices ligula a ullamcorper scelerisque.
+
+           Donec tincidunt felis turpis, id venenatis neque convallis in. Proin euismod ligula nec
+        urna vulputate, sed elementum mauris ultrices. Ut efficitur sem vel mi vestibulum placerat.
+        Sed fermentum lacus nec metus dictum, a commodo quam fermentum. Sed vel vulputate magna.
+        Integer convallis nisi sit amet mi lobortis pellentesque. In egestas porttitor elit eu
+        scelerisque. Suspendisse eleifend vel enim quis tincidunt. Sed placerat risus et pretium
+        porttitor. Nam justo mi, cursus eu pellentesque vel, bibendum ut nisl. Nulla condimentum
+        lorem, non sagittis lorem volutpat vitae. Mauris nec libero lorem. Vestibulum lacus ex,
+        vulputate non massa vitae, pellentesque vestibulum dolor.
+
+           Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+        Suspendisse vitae erat nisl. Vestibulum elit ante, semper et semper sit amet, fringilla
+        sapien. Morbi ac nisi sit amet turpis tincidunt mattis ac eget nisl. Nunc a venenatis quam,
+        facilisis maximus odio. Aliquam erat volutpat. Maecenas leo enim, ornare a magna quis,
+        venenatis ornare nulla. Aliquam venenatis nibh et elit tincidunt, ut egestas lorem finibus.
+        Integer iaculis dolor sed enim blandit vestibulum. Nullam vel libero ultricies, sagittis
+        tortor non, molestie eros.</string>
 </resources>
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ExtraAssistDataActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ExtraAssistDataActivity.java
new file mode 100644
index 0000000..57d34f8
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ExtraAssistDataActivity.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.assist.testapp;
+
+import android.app.Activity;
+import android.app.assist.AssistContent;
+import android.assist.common.Utils;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.Override;
+
+/**
+ * Test the onProvideAssistData and onProvideAssistContent methods activities may override to
+ * provide extra information to the assistant. Verify that the data passed from the activity matches
+ * the data received in {@link android.service.voice.VoiceInteractionSession}.
+ */
+public class ExtraAssistDataActivity extends Activity {
+    private static final String TAG = "ExtraAssistDataActivity";
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public void onProvideAssistData(Bundle data) {
+        super.onProvideAssistData(data);
+        Log.i(TAG, "onProvideAssistData");
+        Utils.addExtraAssistDataToBundle(data);
+    }
+
+    @Override
+    public void onProvideAssistContent(AssistContent outContent) {
+        super.onProvideAssistContent(outContent);
+        Log.i(TAG, "onProvideAssistContent");
+        try {
+            outContent.setStructuredData(Utils.getStructuredJSON());
+        } catch (Exception e) {
+            Log.i(TAG, "Failed to get Structured JSON to put into the AssistContent.");
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java
new file mode 100644
index 0000000..4ab24ed
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 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.assist.testapp;
+
+import android.app.Activity;
+import android.assist.common.Utils;
+import android.content.Intent;
+import android.util.Log;
+
+public class FocusChangeActivity extends Activity {
+    private static final String TAG = "FocusChangeActivity";
+    private boolean mGainedFocus = false;
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        if (hasFocus && !mGainedFocus) {
+            mGainedFocus = true;
+            Log.i(TAG, "gained focus");
+            sendBroadcast(new Intent(Utils.GAINED_FOCUS));
+        } else if (!hasFocus && mGainedFocus) {
+            Log.i(TAG, "lost focus");
+            sendBroadcast(new Intent(Utils.LOST_FOCUS));
+        }
+    }
+}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
index 4e1dc80..af10f99 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
@@ -39,22 +39,22 @@
 
     @Override
     protected void onPause() {
-        super.onPause();
         Log.i(TAG, "activity was paused");
         sendBroadcast(new Intent("android.intent.action.lifecycle_onpause"));
+        super.onPause();
     }
 
     @Override
     protected void onStop() {
-        super.onStop();
         Log.i(TAG, "activity was stopped");
         sendBroadcast(new Intent("android.intent.action.lifecycle_onstop"));
+        super.onStop();
     }
 
     @Override
     protected void onDestroy() {
-        super.onDestroy();
         Log.i(TAG, "activity was destroyed");
         sendBroadcast(new Intent("android.intent.action.lifecycle_ondestroy"));
+        super.onDestroy();
     }
 }
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ScreenshotActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ScreenshotActivity.java
new file mode 100644
index 0000000..581af2e
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ScreenshotActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 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.assist.testapp;
+
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+import java.lang.Override;
+
+public class ScreenshotActivity extends Activity {
+    static final String TAG = "ScreenshotActivity";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "ScreenshotActivity created");
+        setContentView(R.layout.screenshot_activity);
+    }
+
+    @Override
+    public void onResume() {
+        Log.i(TAG, " in onResume");
+        super.onResume();
+        int backgroundColor = getIntent().getIntExtra(Utils.SCREENSHOT_COLOR_KEY, Color.WHITE);
+        View view = findViewById(R.id.screenshot_activity);
+        view.setBackgroundColor(backgroundColor);
+        view.requestLayout();
+
+        // Tell service activity is in foreground.
+        Intent intent = new Intent(Utils.APP_3P_HASRESUMED);
+        sendBroadcast(intent);
+        Log.i(TAG, "Resumed broadcast sent.");
+    }
+
+    @Override
+    public void onPause() {
+        Log.i(TAG, "onPause");
+        finish();
+        super.onPause();
+    }
+}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
index ff56ea8..e0f83cc 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
@@ -20,6 +20,16 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+
+import java.io.ByteArrayOutputStream;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.View;
@@ -31,12 +41,20 @@
 public class TestApp extends Activity {
     static final String TAG = "TestApp";
 
+    private String mTestCaseName;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Log.i(TAG, "TestApp created");
-        setContentView(R.layout.test_app);
+        mTestCaseName = getIntent().getStringExtra(Utils.TESTCASE_TYPE);
+        switch (mTestCaseName) {
+            case Utils.LARGE_VIEW_HIERARCHY:
+                setContentView(R.layout.multiple_text_views);
+                return;
+            default:
+                setContentView(R.layout.test_app);
+        }
     }
 
     @Override
@@ -49,7 +67,7 @@
             @Override
             public void onGlobalLayout() {
                 layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                sendBroadcast(new Intent(Utils.ASSIST_STRUCTURE_HASRESUMED));
+                sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
             }
         });
     }
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TextViewActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TextViewActivity.java
new file mode 100644
index 0000000..9e57e9b
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TextViewActivity.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 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.assist.testapp;
+
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.lang.Override;
+
+public class TextViewActivity extends Activity {
+    static final String TAG = "TextViewActivity";
+
+    private BroadcastReceiver mReceiver;
+    private TextView mTextView;
+    private ScrollView mScrollView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "TextViewActivity created");
+        setContentView(R.layout.text_view);
+        mScrollView = (ScrollView) findViewById(R.id.scroll_view);
+        mTextView = (TextView) findViewById(R.id.text_view);
+        mTextView.setMovementMethod(new ScrollingMovementMethod());
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        Log.i(TAG, "TextViewActivity has resumed");
+
+        mReceiver = new ScrollReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.SCROLL_TEXTVIEW_ACTION);
+        filter.addAction(Utils.SCROLL_SCROLLVIEW_ACTION);
+        registerReceiver(mReceiver, filter);
+
+        final View layout = findViewById(android.R.id.content);
+        ViewTreeObserver vto = layout.getViewTreeObserver();
+        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+            @Override
+            public void onGlobalLayout() {
+                layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
+            }
+        });
+    }
+
+    @Override
+    public void onPause() {
+        if (mReceiver != null) {
+            unregisterReceiver(mReceiver);
+        }
+        super.onPause();
+    }
+
+    class ScrollReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            int scrollX, scrollY;
+            scrollX = intent.getIntExtra(Utils.SCROLL_X_POSITION, 0);
+            scrollY = intent.getIntExtra(Utils.SCROLL_Y_POSITION, 0);
+            if (intent.getAction().equals(Utils.SCROLL_TEXTVIEW_ACTION)) {
+                Log.i(TAG, "Scrolling textview to (" + scrollX + "," + scrollY + ")");
+                if (scrollX < 0 || scrollY < 0) {
+                    // Scroll to bottom as negative positions are not possible.
+                    scrollX = mTextView.getWidth();
+                    scrollY = mTextView.getLayout().getLineTop(mTextView.getLineCount())
+                            - mTextView.getHeight();
+                }
+                TextViewActivity.this.mTextView.scrollTo(scrollX, scrollY);
+            } else if (intent.getAction().equals(Utils.SCROLL_SCROLLVIEW_ACTION)) {
+                Log.i(TAG, "Scrolling scrollview to (" + scrollX + "," + scrollY + ")");
+                if (scrollX < 0 || scrollY < 0) {
+                    // Scroll to bottom
+                    TextViewActivity.this.mScrollView.fullScroll(View.FOCUS_DOWN);
+                    TextViewActivity.this.mScrollView.fullScroll(View.FOCUS_RIGHT);
+                } else {
+                    TextViewActivity.this.mScrollView.scrollTo(scrollX, scrollY);
+                }
+            }
+            Log.i(TAG, "the max height of this textview is: " + mTextView.getHeight());
+            Log.i(TAG, "the max line count of this text view is: " + mTextView.getMaxLines());
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/WebViewActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/WebViewActivity.java
new file mode 100644
index 0000000..59f96cb
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/WebViewActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 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.assist.testapp;
+
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import java.lang.Override;
+
+public class WebViewActivity extends Activity {
+    static final String TAG = "WebViewActivity";
+
+    private String mTestCaseName;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "TestApp created");
+        mTestCaseName = getIntent().getStringExtra(Utils.TESTCASE_TYPE);
+        setContentView(R.layout.webview);
+        WebView webview = (WebView) findViewById(R.id.webview);
+        webview.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url){
+                sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
+            }
+        });
+        webview.loadData(Utils.WEBVIEW_HTML, "text/html", "UTF-8");
+        //webview.loadUrl(
+        //        "https://android-developers.blogspot.com/2015/08/m-developer-preview-3-final-sdk.html");
+    }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
index cc444a6..bc819c1 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -41,6 +41,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -58,6 +59,7 @@
 
     private static final int SCAN_DURATION_MILLIS = 5000;
     private static final int BATCH_SCAN_REPORT_DELAY_MILLIS = 20000;
+    private CountDownLatch mFlushBatchScanLatch;
 
     private BluetoothAdapter mBluetoothAdapter;
     private BluetoothLeScanner mScanner;
@@ -215,8 +217,14 @@
                 batchScanCallback);
         sleep(SCAN_DURATION_MILLIS);
         mScanner.flushPendingScanResults(batchScanCallback);
-        sleep(1000);
+        mFlushBatchScanLatch = new CountDownLatch(1);
         List<ScanResult> results = batchScanCallback.getBatchScanResults();
+        try {
+            mFlushBatchScanLatch.await(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // Nothing to do.
+            Log.e(TAG, "interrupted!");
+        }
         assertTrue(!results.isEmpty());
         long scanEndMillis = SystemClock.elapsedRealtime();
         mScanner.stopScan(batchScanCallback);
@@ -252,6 +260,9 @@
             // In case onBatchScanResults are called due to buffer full, we want to collect all
             // scan results.
             mBatchScanResults.addAll(results);
+            if (mFlushBatchScanLatch != null) {
+                mFlushBatchScanLatch.countDown();
+            }
         }
 
         // Clear regular and batch scan results.
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
index 75de9c0..41e2045 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
@@ -714,6 +714,7 @@
 
                     // clear out the surface and camera session
                     stopPreviewAndClearSurface(previewBuilder, rawBurstBuilder);
+                    rawReaderListener.drain();
                     closeImageReader();
                 }
             } finally {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index c5eb27b..d78b3b5 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -337,7 +337,7 @@
          *
          */
         public void drain() {
-            for (int i = 0; i < mQueue.size(); i++) {
+            while (!mQueue.isEmpty()) {
                 Image image = mQueue.poll();
                 assertNotNull("Unable to get an image", image);
                 image.close();
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 9e75d94..dd4e3e3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -69,7 +69,8 @@
     private static final long EXPOSURE_TIME_BOUNDARY_50HZ_NS = 10000000L; // 10ms
     private static final long EXPOSURE_TIME_BOUNDARY_60HZ_NS = 8333333L; // 8.3ms, Approximation.
     private static final long EXPOSURE_TIME_ERROR_MARGIN_NS = 100000L; // 100us, Approximation.
-    private static final int SENSITIVITY_ERROR_MARGIN = 10; // 10
+    private static final float EXPOSURE_TIME_ERROR_MARGIN_RATE = 0.03f; // 3%, Approximation.
+    private static final float SENSITIVITY_ERROR_MARGIN_RATE = 0.03f; // 3%, Approximation.
     private static final int DEFAULT_NUM_EXPOSURE_TIME_STEPS = 3;
     private static final int DEFAULT_NUM_SENSITIVITY_STEPS = 16;
     private static final int DEFAULT_SENSITIVITY_STEP_SIZE = 100;
@@ -1711,9 +1712,10 @@
         // video stabilization test.
         List<Key<?>> keys = mStaticInfo.getCharacteristics().getKeys();
 
-        int[] videoStabModes = (keys.contains(CameraCharacteristics.
+        Integer[] videoStabModes = (keys.contains(CameraCharacteristics.
                 CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)) ?
-                mStaticInfo.getAvailableVideoStabilizationModesChecked() : new int[0];
+                CameraTestUtils.toObject(mStaticInfo.getAvailableVideoStabilizationModesChecked()) :
+                    new Integer[0];
         int[] opticalStabModes = (keys.contains(
                 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) ?
                 mStaticInfo.getAvailableOpticalStabilizationChecked() : new int[0];
@@ -1724,13 +1726,14 @@
         SimpleCaptureCallback listener = new SimpleCaptureCallback();
         startPreview(requestBuilder, maxPreviewSize, listener);
 
-        for (int mode : videoStabModes) {
+        for (Integer mode : videoStabModes) {
             listener = new SimpleCaptureCallback();
             requestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, mode);
             mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
             waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
-            verifyCaptureResultForKey(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE, mode,
-                    listener, NUM_FRAMES_VERIFIED);
+            // Video stabilization could return any modes.
+            verifyAnyCaptureResultForKey(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE,
+                    videoStabModes, listener, NUM_FRAMES_VERIFIED);
         }
 
         for (int mode : opticalStabModes) {
@@ -2093,10 +2096,12 @@
      */
     private void validateExposureTime(long request, long result) {
         long expTimeDelta = request - result;
+        long expTimeErrorMargin = (long)(Math.max(EXPOSURE_TIME_ERROR_MARGIN_NS, request
+                * EXPOSURE_TIME_ERROR_MARGIN_RATE));
         // First, round down not up, second, need close enough.
         mCollector.expectTrue("Exposture time is invalid for AE manaul control test, request: "
                 + request + " result: " + result,
-                expTimeDelta < EXPOSURE_TIME_ERROR_MARGIN_NS && expTimeDelta >= 0);
+                expTimeDelta < expTimeErrorMargin && expTimeDelta >= 0);
     }
 
     /**
@@ -2106,11 +2111,12 @@
      * @param result Result sensitivity
      */
     private void validateSensitivity(int request, int result) {
-        int sensitivityDelta = request - result;
+        float sensitivityDelta = (float)(request - result);
+        float sensitivityErrorMargin = request * SENSITIVITY_ERROR_MARGIN_RATE;
         // First, round down not up, second, need close enough.
         mCollector.expectTrue("Sensitivity is invalid for AE manaul control test, request: "
                 + request + " result: " + result,
-                sensitivityDelta < SENSITIVITY_ERROR_MARGIN && sensitivityDelta >= 0);
+                sensitivityDelta < sensitivityErrorMargin && sensitivityDelta >= 0);
     }
 
     /**
@@ -2158,6 +2164,30 @@
     }
 
     /**
+     * Basic verification that the value of a capture result key should be one of the expected
+     * values.
+     *
+     * @param key The capture result key to be verified against
+     * @param expectedModes The list of any possible expected modes for this result
+     * @param listener The capture listener to get capture results
+     * @param numFramesVerified The number of capture results to be verified
+     */
+    private <T> void verifyAnyCaptureResultForKey(CaptureResult.Key<T> key, T[] expectedModes,
+            SimpleCaptureCallback listener, int numFramesVerified) {
+        for (int i = 0; i < numFramesVerified; i++) {
+            CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+            validatePipelineDepth(result);
+            T resultMode = getValueNotNull(result, key);
+            if (VERBOSE) {
+                Log.v(TAG, "Expect values: " + Arrays.toString(expectedModes) + " result value: "
+                        + resultMode.toString());
+            }
+            // Capture result should be one of the expected values.
+            mCollector.expectContains(expectedModes, resultMode);
+        }
+    }
+
+    /**
      * Verify if the fps is slow down for given input request with certain
      * controls inside.
      * <p>
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
index dc499ba..2ae29c3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -316,18 +316,24 @@
                         session, previewBuilder.build(), mHandler);
 
                 // Check if all timestamps are the same
+                Image prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 1", result.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result.second);
+                        prevImage, result.second);
+                prevImage.close();
 
                 // Capture targeting both jpeg and preview
                 Pair<TotalCaptureResult, Long> result2 = captureAndVerifyResult(mockCaptureCallback,
                         session, multiBuilder.build(), mHandler);
 
                 // Check if all timestamps are the same
+                prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+                Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 2 Preview", result2.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
+                        prevImage, result2.second);
                 validateTimestamps("Result 2 Jpeg", result2.first,
-                        jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
+                        jpegImage, result2.second);
+                prevImage.close();
+                jpegImage.close();
 
                 // Check if timestamps are increasing
                 mCollector.expectGreater("Timestamps must be increasing.", result.second,
@@ -343,10 +349,14 @@
                 long resultDiff = result4.second - result3.second;
 
                 // Check if all timestamps are the same
+                prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 3", result3.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result3.second);
+                        prevImage, result3.second);
+                prevImage.close();
+                prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 4", result4.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result4.second);
+                        prevImage, result4.second);
+                prevImage.close();
 
                 // Check that the timestamps monotonically increase at a reasonable rate
                 mCollector.expectGreaterOrEqual("Timestamps increase faster than system clock.",
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 7c80c7d..f1115c4 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -460,6 +460,10 @@
 
                             // Stop capture, delete the streams.
                             stopCapture(/*fast*/false);
+                            yuvImage.close();
+                            jpegImage.close();
+                            yuvListener.drain();
+                            jpegListener.drain();
                         } finally {
                             closeImageReader(jpegReader);
                             jpegReader = null;
@@ -645,6 +649,8 @@
                             maxYuvSz.getHeight(), ImageFormat.YUV_420_888, /*filePath*/null);
                     CameraTestUtils.validateImage(captureImage, captureSz.getWidth(),
                             captureSz.getHeight(), format, /*filePath*/null);
+                    yuvImage.close();
+                    captureImage.close();
                 }
 
                 // Stop capture, delete the streams.
@@ -788,7 +794,7 @@
                                     getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME),
                                     TEST_EXPOSURE_TIME_NS),
                             exposureTimeDiff < EXPOSURE_TIME_ERROR_MARGIN_NS &&
-                            exposureTimeDiff > 0);
+                            exposureTimeDiff >= 0);
 
                     mCollector.expectTrue(
                             String.format("Long processing frame %d format %d size %s " +
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
index dfba587..2795bde 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
@@ -78,7 +78,7 @@
             Exception prior = null;
 
             ImageVerifierListener yuvListener;
-            ImageReader yuvReader;
+            ImageReader yuvReader = null;
 
             try {
                 openCamera(cameraId);
@@ -102,6 +102,9 @@
                 prior = e;
             } finally {
                 try {
+                    if (yuvReader != null) {
+                        yuvReader.close();
+                    }
                     closeCamera(cameraId);
                 } catch (Exception e) {
                     if (prior != null) {
@@ -151,7 +154,7 @@
             Exception prior = null;
 
             ImageVerifierListener yuvListener;
-            ImageReader yuvReader;
+            ImageReader yuvReader = null;
 
             try {
                 openCamera(cameraId);
@@ -175,6 +178,9 @@
                 prior = e;
             } finally {
                 try {
+                    if (yuvReader != null) {
+                        yuvReader.close();
+                    }
                     closeCamera(cameraId);
                 } catch (Exception e) {
                     if (prior != null) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
index 4af88ca..39eb1dc 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -66,13 +66,12 @@
     private static final int NUM_MAX_IMAGES = 4;
     private static final int NUM_RESULTS_WAIT = 30;
     private static final int[] REPROCESS_FORMATS = {ImageFormat.YUV_420_888, ImageFormat.PRIVATE};
-    private final int MAX_REPROCESS_IMAGES = 10;
+    private final int MAX_REPROCESS_IMAGES = 6;
     private final int MAX_JPEG_IMAGES = MAX_REPROCESS_IMAGES;
     private final int MAX_INPUT_IMAGES = MAX_REPROCESS_IMAGES;
     // ZSL queue depth should be bigger than the max simultaneous reprocessing capture request
     // count to maintain reasonable number of candidate image for the worse-case.
-    // Here we want to make sure we at most dequeue half of the queue max images for the worst-case.
-    private final int MAX_ZSL_IMAGES = MAX_REPROCESS_IMAGES * 2;
+    private final int MAX_ZSL_IMAGES = MAX_REPROCESS_IMAGES * 3 / 2;
     private final double REPROCESS_STALL_MARGIN = 0.1;
 
     private DeviceReportLog mReportLog;
@@ -434,7 +433,7 @@
             // Wait for reprocess output jpeg and result come back.
             reprocessResultListener.getCaptureResultForRequest(reprocessRequest,
                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
-            mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+            mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS).close();
             long numFramesMaybeStalled = mZslResultListener.getTotalNumFrames();
             assertTrue("Reprocess capture result should be returned in "
                     + MAX_REPROCESS_RETURN_FRAME_COUNT + " frames",
@@ -475,6 +474,8 @@
             maxCaptureGapsMs[i] = maxTimestampGapMs;
         }
 
+        stopZslStreaming();
+
         String reprocessType = " YUV reprocessing ";
         if (reprocessInputFormat == ImageFormat.PRIVATE) {
             reprocessType = " opaque reprocessing ";
@@ -539,24 +540,34 @@
 
             // Get images
             startTimeMs = SystemClock.elapsedRealtime();
+            Image jpegImages[] = new Image[MAX_REPROCESS_IMAGES];
             for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
-                mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+                jpegImages[i] = mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
                 getImageLatenciesMs[i] = SystemClock.elapsedRealtime() - startTimeMs;
                 startTimeMs = SystemClock.elapsedRealtime();
             }
+            for (Image i : jpegImages) {
+                i.close();
+            }
         } else {
             // sync capture: issue reprocess request one by one, only submit next one when
             // the previous capture image is returned. This is to test the back to back capture
             // performance.
+            Image jpegImages[] = new Image[MAX_REPROCESS_IMAGES];
             for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
                 startTimeMs = SystemClock.elapsedRealtime();
                 mWriter.queueInputImage(inputImages[i]);
                 mSession.capture(reprocessReqs[i].build(), null, null);
-                mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+                jpegImages[i] = mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
                 getImageLatenciesMs[i] = SystemClock.elapsedRealtime() - startTimeMs;
             }
+            for (Image i : jpegImages) {
+                i.close();
+            }
         }
 
+        stopZslStreaming();
+
         String reprocessType = " YUV reprocessing ";
         if (reprocessInputFormat == ImageFormat.PRIVATE) {
             reprocessType = " opaque reprocessing ";
@@ -591,6 +602,12 @@
         mSession.setRepeatingRequest(zslBuilder.build(), mZslResultListener, mHandler);
     }
 
+    private void stopZslStreaming() throws Exception {
+        mSession.stopRepeating();
+        mSessionListener.getStateWaiter().waitForState(
+            BlockingSessionCallback.SESSION_READY, CameraTestUtils.CAMERA_IDLE_TIMEOUT_MS);
+    }
+
     /**
      * Wait for a certain number of frames, the images and results will be drained from the
      * listeners to make sure that next reprocessing can get matched results and images.
@@ -598,24 +615,22 @@
      * @param numFrameWait The number of frames to wait before return, 0 means that
      *      this call returns immediately after streaming on.
      */
-    private void waitForFrames(int numFrameWait) {
+    private void waitForFrames(int numFrameWait) throws Exception {
         if (numFrameWait < 0) {
             throw new IllegalArgumentException("numFrameWait " + numFrameWait +
                     " should be non-negative");
         }
 
-        if (numFrameWait == 0) {
-            // Let is stream out for a while
-            waitForNumResults(mZslResultListener, numFrameWait);
-            // Drain the pending images, to ensure that all future images have an associated
-            // capture result available.
-            mCameraZslImageListener.drain();
+        for (int i = 0; i < numFrameWait; i++) {
+            mCameraZslImageListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS).close();
         }
     }
 
     private void closeReaderWriters() {
+        mCameraZslImageListener.drain();
         CameraTestUtils.closeImageReader(mCameraZslReader);
         mCameraZslReader = null;
+        mJpegListener.drain();
         CameraTestUtils.closeImageReader(mJpegReader);
         mJpegReader = null;
         CameraTestUtils.closeImageWriter(mWriter);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index 52fd69f..de0e3d5 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -14,6 +14,7 @@
 import static android.hardware.camera2.cts.CameraTestUtils.*;
 import static com.android.ex.camera2.blocking.BlockingSessionCallback.*;
 
+import android.cts.util.MediaUtils;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraCaptureSession;
@@ -151,6 +152,9 @@
      * </p>
      */
     public void testRecordingFromPersistentSurface() throws Exception {
+        if (!MediaUtils.checkCodecForDomain(true /* encoder */, "video")) {
+            return; // skipped
+        }
         mPersistentSurface = MediaCodec.createPersistentInputSurface();
         assertNotNull("Failed to create persistent input surface!", mPersistentSurface);
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
index 8a60dc2..dd49c8d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
@@ -1211,6 +1211,9 @@
             throw new IllegalArgumentException("isReprocessCaptures must have at least 1 capture.");
         }
 
+        boolean hasReprocessRequest = false;
+        boolean hasRegularRequest = false;
+
         TotalCaptureResult[] results = new TotalCaptureResult[isReprocessCaptures.length];
         for (int i = 0; i < isReprocessCaptures.length; i++) {
             // submit a capture and get the result if this entry is a reprocess capture.
@@ -1219,6 +1222,9 @@
                         /*inputResult*/null);
                 mImageWriter.queueInputImage(
                         mFirstImageReaderListener.getImage(CAPTURE_TIMEOUT_MS));
+                hasReprocessRequest = true;
+            } else {
+                hasRegularRequest = true;
             }
         }
 
@@ -1232,7 +1238,24 @@
         ImageResultHolder[] holders = new ImageResultHolder[isReprocessCaptures.length];
         for (int i = 0; i < isReprocessCaptures.length; i++) {
             Image image = getReprocessOutputImageReaderListener().getImage(CAPTURE_TIMEOUT_MS);
-            holders[i] = new ImageResultHolder(image, finalResults[i]);
+            if (hasReprocessRequest && hasRegularRequest) {
+                // If there are mixed requests, images and results may not be in the same order.
+                for (int j = 0; j < finalResults.length; j++) {
+                    if (finalResults[j] != null &&
+                            finalResults[j].get(CaptureResult.SENSOR_TIMESTAMP) ==
+                            image.getTimestamp()) {
+                        holders[i] = new ImageResultHolder(image, finalResults[j]);
+                        finalResults[j] = null;
+                        break;
+                    }
+                }
+
+                assertNotNull("Cannot find a result matching output image's timestamp: " +
+                        image.getTimestamp(), holders[i]);
+            } else {
+                // If no mixed requests, images and results should be in the same order.
+                holders[i] = new ImageResultHolder(image, finalResults[i]);
+            }
         }
 
         return holders;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
index 8ccc931..ddae8eb 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -1351,8 +1351,8 @@
         Log.i(TAG, String.format("Testing Camera %s, config %s",
                         cameraId, MaxStreamSizes.configToString(config)));
 
-        // Timeout is relaxed by 500ms for LEGACY devices to reduce false positive rate in CTS
-        final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 1500 : 1000;
+        // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS
+        final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 2000 : 1000;
         final int MIN_RESULT_COUNT = 3;
 
         // Set up outputs
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
index 68efef0..a2ddb4d 100755
--- a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
@@ -105,7 +105,7 @@
             if (supports64Bit) {
                 assertMinMemoryMb(1824);
             } else {
-                assertMinMemoryMb(1344);
+                assertMinMemoryMb(1099);
             }
         } else if (greaterThanDpi(density, DENSITY_400, screenSize,
                 SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
index c807e03..22f092a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
@@ -102,13 +102,13 @@
                 sensor.getMaximumRange() >= maxRange);
         double actualMinFrequency = SensorCtsHelper.getFrequency(sensor.getMaxDelay(),
                 TimeUnit.MICROSECONDS);
-        assertTrue(String.format("%s Min Frequency actual=%.2f expected=%dHz",
+        assertTrue(String.format("%s Min Frequency actual=%.2f expected=%.2fHz",
                     sensor.getName(), actualMinFrequency, minFrequency), actualMinFrequency <=
                 minFrequency + 0.1);
 
         double actualMaxFrequency = SensorCtsHelper.getFrequency(sensor.getMinDelay(),
                 TimeUnit.MICROSECONDS);
-        assertTrue(String.format("%s Max Frequency actual=%.2f expected=%dHz",
+        assertTrue(String.format("%s Max Frequency actual=%.2f expected=%.2fHz",
                     sensor.getName(), actualMaxFrequency, maxFrequency), actualMaxFrequency >=
                 maxFrequency - 0.1);
     }
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index 2c3c6f4..cffafdc 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -88,7 +88,7 @@
     }
 
     @Override
-    protected void tearDown(){
+    protected void tearDown() {
         if (mSensorManager != null) {
             // SensorManager will check listener and status, so just unregister listener
             mSensorManager.unregisterListener(mNullSensorEventListener);
@@ -256,7 +256,8 @@
         if (mTriggerSensor == null) {
             throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
         }
-        boolean  result = mSensorManager.requestTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
+        boolean  result =
+            mSensorManager.requestTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
         assertFalse(result);
     }
 
@@ -265,7 +266,8 @@
         if (mTriggerSensor == null) {
             throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
         }
-        boolean result = mSensorManager.cancelTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
+        boolean result =
+            mSensorManager.cancelTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
         assertFalse(result);
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
index 55465ac..9cb3710 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -38,21 +38,32 @@
     private SensorCtsHelper() {}
 
     /**
-     * Get the value of the 95th percentile using nearest rank algorithm.
+     * Get percentiles using nearest rank algorithm.
      *
-     * @throws IllegalArgumentException if the collection is null or empty
+     * @param percentiles List of percentiles interested. Its range is 0 to 1, instead of in %.
+     *        The value will be internally bounded.
+     *
+     * @throws IllegalArgumentException if the collection or percentiles is null or empty
      */
-    public static <TValue extends Comparable<? super TValue>> TValue get95PercentileValue(
-            Collection<TValue> collection) {
+    public static <TValue extends Comparable<? super TValue>> List<TValue> getPercentileValue(
+            Collection<TValue> collection, float[] percentiles) {
         validateCollection(collection);
+        if(percentiles == null || percentiles.length == 0) {
+            throw new IllegalStateException("percentiles cannot be null or empty");
+        }
 
         List<TValue> arrayCopy = new ArrayList<TValue>(collection);
         Collections.sort(arrayCopy);
 
-        // zero-based array index
-        int arrayIndex = (int) Math.round(arrayCopy.size() * 0.95 + .5) - 1;
-
-        return arrayCopy.get(arrayIndex);
+        List<TValue> percentileValues = new ArrayList<TValue>();
+        for (float p : percentiles) {
+            // zero-based array index
+            int arrayIndex = (int) Math.round(arrayCopy.size() * p - .5f);
+            // bound the index to avoid out of range error
+            arrayIndex = Math.min(Math.max(arrayIndex, 0), arrayCopy.size() - 1);
+            percentileValues.add(arrayCopy.get(arrayIndex));
+        }
+        return percentileValues;
     }
 
     /**
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 3e70e75..e8df1ab 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -172,8 +172,7 @@
      */
     public List<TestSensorEvent> getCollectedEvents() {
         synchronized (mCollectedEvents){
-            List<TestSensorEvent> collectedEventsList = (List)mCollectedEvents.clone();
-            return Collections.unmodifiableList(collectedEventsList);
+            return Collections.unmodifiableList((List<TestSensorEvent>) mCollectedEvents.clone());
         }
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
index d246ec5..9d36f37 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
@@ -16,8 +16,6 @@
 
 package android.hardware.cts.helpers.sensorverification;
 
-import junit.framework.Assert;
-
 import android.content.Context;
 import android.content.pm.PackageManager;
 
@@ -34,6 +32,7 @@
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import junit.framework.Assert;
 
 /**
  * A {@link ISensorVerification} which verifies that the sensor jitter is in an acceptable range.
@@ -43,15 +42,22 @@
 
     // sensorType: threshold (% of expected period)
     private static final SparseIntArray DEFAULTS = new SparseIntArray(12);
-    // Max allowed jitter (in percentage).
+    // Max allowed jitter in +/- sense (in percentage).
     private static final int GRACE_FACTOR = 2;
     private static final int THRESHOLD_PERCENT_FOR_HIFI_SENSORS = 1 * GRACE_FACTOR;
+
+    // Margin sample intervals that considered outliers, lower and higher margin is discarded
+    // before verification
+    private static final float OUTLIER_MARGIN = 0.025f; //2.5%
+
     static {
         // Use a method so that the @deprecation warning can be set for that method only
         setDefaults();
     }
 
-    private final int mThresholdAsPercentage;
+    private final float     mOutlierMargin;
+    private final long      mThresholdNs;
+    private final long      mExpectedPeriodNs; // for error message only
     private final List<Long> mTimestamps = new LinkedList<Long>();
 
     /**
@@ -59,8 +65,10 @@
      *
      * @param thresholdAsPercentage the acceptable margin of error as a percentage
      */
-    public JitterVerification(int thresholdAsPercentage) {
-        mThresholdAsPercentage = thresholdAsPercentage;
+    public JitterVerification(float outlierMargin, long thresholdNs, long expectedPeriodNs) {
+        mExpectedPeriodNs = expectedPeriodNs;
+        mOutlierMargin = outlierMargin;
+        mThresholdNs = thresholdNs;
     }
 
     /**
@@ -71,16 +79,20 @@
      */
     public static JitterVerification getDefault(TestSensorEnvironment environment) {
         int sensorType = environment.getSensor().getType();
-        int threshold = DEFAULTS.get(sensorType, -1);
-        if (threshold == -1) {
+
+        int thresholdPercent = DEFAULTS.get(sensorType, -1);
+        if (thresholdPercent == -1) {
             return null;
         }
         boolean hasHifiSensors = environment.getContext().getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_HIFI_SENSORS);
         if (hasHifiSensors) {
-           threshold = THRESHOLD_PERCENT_FOR_HIFI_SENSORS;
+           thresholdPercent = THRESHOLD_PERCENT_FOR_HIFI_SENSORS;
         }
-        return new JitterVerification(threshold);
+
+        long expectedPeriodNs = (long) environment.getExpectedSamplingPeriodUs() * 1000;
+        long jitterThresholdNs = expectedPeriodNs * thresholdPercent * 2 / 100; // *2 is for +/-
+        return new JitterVerification(OUTLIER_MARGIN, jitterThresholdNs, expectedPeriodNs);
     }
 
     /**
@@ -99,24 +111,33 @@
             return;
         }
 
-        List<Double> jitters = getJitterValues();
-        double jitter95PercentileNs = SensorCtsHelper.get95PercentileValue(jitters);
-        long firstTimestamp = mTimestamps.get(0);
-        long lastTimestamp = mTimestamps.get(timestampsCount - 1);
-        long measuredPeriodNs = (lastTimestamp - firstTimestamp) / (timestampsCount - 1);
-        double jitter95PercentilePercent = (jitter95PercentileNs * 100.0) / measuredPeriodNs;
-        stats.addValue(SensorStats.JITTER_95_PERCENTILE_PERCENT_KEY, jitter95PercentilePercent);
+        List<Long> deltas = getDeltaValues();
+        float percentiles[] = new float[2];
+        percentiles[0] = mOutlierMargin;
+        percentiles[1] = 1 - percentiles[0];
 
-        boolean success = (jitter95PercentilePercent < mThresholdAsPercentage);
+        List<Long> percentileValues = SensorCtsHelper.getPercentileValue(deltas, percentiles);
+        double normalizedRange =
+                (double)(percentileValues.get(1) - percentileValues.get(0)) / mThresholdNs;
+
+        double percentageJitter =
+                (double)(percentileValues.get(1) - percentileValues.get(0)) /
+                        mExpectedPeriodNs / 2 * 100; //one side variation comparing to sample time
+
+        stats.addValue(SensorStats.JITTER_95_PERCENTILE_PERCENT_KEY, percentageJitter);
+
+        boolean success = normalizedRange <= 1.0;
         stats.addValue(PASSED_KEY, success);
 
         if (!success) {
             String message = String.format(
-                    "Jitter out of range: measured period=%dns, jitter(95th percentile)=%.2f%%"
-                            + " (expected < %d%%)",
-                    measuredPeriodNs,
-                    jitter95PercentilePercent,
-                    mThresholdAsPercentage);
+                    "Jitter out of range: requested period = %dns, " +
+                    "jitter min, max, range (95th percentile) = (%dns, %dns, %dns), " +
+                    "jitter expected range <= %dns",
+                    mExpectedPeriodNs,
+                    percentileValues.get(0), percentileValues.get(1),
+                    percentileValues.get(1) - percentileValues.get(0),
+                    mThresholdNs);
             Assert.fail(message);
         }
     }
@@ -126,7 +147,7 @@
      */
     @Override
     public JitterVerification clone() {
-        return new JitterVerification(mThresholdAsPercentage);
+        return new JitterVerification(mOutlierMargin, mThresholdNs, mExpectedPeriodNs);
     }
 
     /**
@@ -138,19 +159,14 @@
     }
 
     /**
-     * Get the list of all jitter values. Exposed for unit testing.
+     * Get the list of delta values. Exposed for unit testing.
      */
-    List<Double> getJitterValues() {
+    List<Long> getDeltaValues() {
         List<Long> deltas = new ArrayList<Long>(mTimestamps.size() - 1);
         for (int i = 1; i < mTimestamps.size(); i++) {
             deltas.add(mTimestamps.get(i) - mTimestamps.get(i - 1));
         }
-        double deltaMean = StatisticsUtils.getMean(deltas);
-        List<Double> jitters = new ArrayList<Double>(deltas.size());
-        for (long delta : deltas) {
-            jitters.add(Math.abs(delta - deltaMean));
-        }
-        return jitters;
+        return deltas;
     }
 
     @SuppressWarnings("deprecation")
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
index 50e288c..d8e1586 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
@@ -27,11 +27,10 @@
 import java.util.List;
 
 /**
- * Tests for {@link EventOrderingVerification}.
+ * Tests for {@link JitterVerification}.
  */
 public class JitterVerificationTest extends TestCase {
 
-
     public void testVerify() {
         final int SAMPLE_SIZE = 100;
         // for unit testing the verification, only the parameter 'sensorMightHaveMoreListeners' is
@@ -67,54 +66,58 @@
         } catch (AssertionError e) {
             // Expected;
         }
-        verifyStats(stats, false, 47.34);
+        verifyStats(stats, false, 25); // 500 us range (250 us in single-sided sense)
+                                       // divide by 1ms requested sample time x 100%
     }
 
-    public void testCalculateJitter() {
+    public void testCalculateDelta() {
         long[] timestamps = new long[]{0, 1, 2, 3, 4};
         JitterVerification verification = getVerification(1, timestamps);
-        List<Double> jitterValues = verification.getJitterValues();
-        assertEquals(4, jitterValues.size());
-        assertEquals(0.0, jitterValues.get(0));
-        assertEquals(0.0, jitterValues.get(1));
-        assertEquals(0.0, jitterValues.get(2));
-        assertEquals(0.0, jitterValues.get(3));
+        List<Long> deltaValues = verification.getDeltaValues();
+        assertEquals(4, deltaValues.size());
+        assertEquals(1, deltaValues.get(0).longValue());
+        assertEquals(1, deltaValues.get(1).longValue());
+        assertEquals(1, deltaValues.get(2).longValue());
+        assertEquals(1, deltaValues.get(3).longValue());
 
         timestamps = new long[]{0, 0, 2, 4, 4};
         verification = getVerification(1, timestamps);
-        jitterValues = verification.getJitterValues();
-        assertEquals(4, jitterValues.size());
-        assertEquals(1.0, jitterValues.get(0));
-        assertEquals(1.0, jitterValues.get(1));
-        assertEquals(1.0, jitterValues.get(2));
-        assertEquals(1.0, jitterValues.get(3));
+        deltaValues = verification.getDeltaValues();
+        assertEquals(4, deltaValues.size());
+        assertEquals(0, deltaValues.get(0).longValue());
+        assertEquals(2, deltaValues.get(1).longValue());
+        assertEquals(2, deltaValues.get(2).longValue());
+        assertEquals(0, deltaValues.get(3).longValue());
 
         timestamps = new long[]{0, 1, 4, 9, 16};
         verification = getVerification(1, timestamps);
-        jitterValues = verification.getJitterValues();
-        assertEquals(4, jitterValues.size());
-        assertEquals(4, jitterValues.size());
-        assertEquals(3.0, jitterValues.get(0));
-        assertEquals(1.0, jitterValues.get(1));
-        assertEquals(1.0, jitterValues.get(2));
-        assertEquals(3.0, jitterValues.get(3));
+        deltaValues = verification.getDeltaValues();
+        assertEquals(4, deltaValues.size());
+        assertEquals(1, deltaValues.get(0).longValue());
+        assertEquals(3, deltaValues.get(1).longValue());
+        assertEquals(5, deltaValues.get(2).longValue());
+        assertEquals(7, deltaValues.get(3).longValue());
     }
 
-    private static JitterVerification getVerification(int threshold, long ... timestamps) {
+    private static JitterVerification getVerification(int marginPercent, long ... timestamps) {
         Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
         for (long timestamp : timestamps) {
             events.add(new TestSensorEvent(null, timestamp, 0, null));
         }
-        JitterVerification verification = new JitterVerification(threshold);
+        long samplePeriodNs = 1000*1000; //1000Hz
+        long jitterThresholdNs = 20*1000; // 2% of that
+
+        JitterVerification verification =
+                new JitterVerification(marginPercent/100.0f, jitterThresholdNs, samplePeriodNs);
         verification.addSensorEvents(events);
         return verification;
     }
 
-    private void verifyStats(SensorStats stats, boolean passed, double jitter95) {
+    private void verifyStats(SensorStats stats, boolean passed, double percentageJitter) {
         assertEquals(passed, stats.getValue(JitterVerification.PASSED_KEY));
         assertEquals(
-                jitter95,
+                percentageJitter,
                 (Double) stats.getValue(SensorStats.JITTER_95_PERCENTILE_PERCENT_KEY),
-                0.1);
+                0.01);
     }
 }
diff --git a/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4 b/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4
new file mode 100644
index 0000000..110c0d6
--- /dev/null
+++ b/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4 b/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4
old mode 100644
new mode 100755
index b837dc2..f88fe7a
--- a/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4
+++ b/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 4c03183..9ae6b64 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -1646,6 +1646,7 @@
                     Thread.sleep(WAIT_MSEC); // wait for the data to drain.
                     // -------- tear down --------------
                     track.release();
+                    Thread.sleep(WAIT_MSEC); // wait for release to complete
                     frequency += 50; // increment test tone frequency
                 }
             }
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
index 9da229c..8650d20 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -20,6 +20,8 @@
 import android.content.res.AssetFileDescriptor;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.CodecProfileLevel;
 import android.media.MediaCodecList;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
@@ -1141,4 +1143,87 @@
     private static String getMimeTypeFor(MediaFormat format) {
         return format.getString(MediaFormat.KEY_MIME);
     }
+
+    /**
+     * Returns the first codec capable of encoding the specified MIME type, or null if no match was
+     * found.
+     */
+    private static MediaCodecInfo selectCodec(String mimeType) {
+        int numCodecs = MediaCodecList.getCodecCount();
+        for (int i = 0; i < numCodecs; i++) {
+            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
+
+            if (!codecInfo.isEncoder()) {
+                continue;
+            }
+
+            String[] types = codecInfo.getSupportedTypes();
+            for (int j = 0; j < types.length; j++) {
+                if (types[j].equalsIgnoreCase(mimeType)) {
+                    return codecInfo;
+                }
+            }
+        }
+        return null;
+    }
+
+  /**
+   * Checks whether the given resolution is supported by the AVC codec.
+   */
+    private static boolean isAvcSupportedSize(int width, int height) {
+        MediaCodecInfo mediaCodecInfo = selectCodec(OUTPUT_VIDEO_MIME_TYPE);
+        CodecCapabilities cap = mediaCodecInfo.getCapabilitiesForType(OUTPUT_VIDEO_MIME_TYPE);
+        if (cap == null) { // not supported
+            return false;
+        }
+        int highestLevel = 0;
+        for (CodecProfileLevel lvl : cap.profileLevels) {
+            if (lvl.level > highestLevel) {
+                highestLevel = lvl.level;
+            }
+        }
+        int maxW = 0;
+        int maxH = 0;
+        int bitRate = 0;
+        int fps = 0; // frame rate for the max resolution
+        switch(highestLevel) {
+            // Do not support Level 1 to 2.
+            case CodecProfileLevel.AVCLevel1:
+            case CodecProfileLevel.AVCLevel11:
+            case CodecProfileLevel.AVCLevel12:
+            case CodecProfileLevel.AVCLevel13:
+            case CodecProfileLevel.AVCLevel1b:
+            case CodecProfileLevel.AVCLevel2:
+                return false;
+            case CodecProfileLevel.AVCLevel21:
+                maxW = 352;
+                maxH = 576;
+                break;
+            case CodecProfileLevel.AVCLevel22:
+                maxW = 720;
+                maxH = 480;
+                break;
+            case CodecProfileLevel.AVCLevel3:
+                maxW = 720;
+                maxH = 480;
+                break;
+            case CodecProfileLevel.AVCLevel31:
+                maxW = 1280;
+                maxH = 720;
+                break;
+            case CodecProfileLevel.AVCLevel32:
+                maxW = 1280;
+                maxH = 720;
+                break;
+            case CodecProfileLevel.AVCLevel4: // only try up to 1080p
+            default:
+                maxW = 1920;
+                maxH = 1080;
+                break;
+        }
+        if(maxW*maxH < width*height)
+            return false;
+        else
+            return true;
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/JetPlayerTest.java b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
index fc03bcc..4df3555 100644
--- a/tests/tests/media/src/android/media/cts/JetPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
@@ -55,6 +55,10 @@
 
     @Override
     protected void tearDown() throws Exception {
+        // Prevent tests from failing with EAS_ERROR_FILE_ALREADY_OPEN
+        // after a previous test fails.
+        mJetPlayer.closeJetFile();
+
         File jetFile = new File(mJetFile);
         if (jetFile.exists()) {
             jetFile.delete();
@@ -63,31 +67,32 @@
     }
 
     public void testLoadJetFromPath() throws Throwable {
-        mJetPlayer.clearQueue();
+        assertTrue(mJetPlayer.clearQueue());
         prepareFile();
         mJetPlayer.setEventListener(mOnJetEventListener);
-        mJetPlayer.loadJetFile(mJetFile);
+        assertTrue(mJetPlayer.loadJetFile(mJetFile));
         runJet();
     }
 
     public void testLoadJetFromFd() throws Throwable {
-        mJetPlayer.clearQueue();
+        assertTrue(mJetPlayer.clearQueue());
         mJetPlayer.setEventListener(mOnJetEventListener, mHandler);
-        mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet));
+        assertTrue(mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet)));
         runJet();
     }
 
     public void testQueueJetSegmentMuteArray() throws Throwable {
-        mJetPlayer.clearQueue();
+        assertTrue(mJetPlayer.clearQueue());
         mJetPlayer.setEventListener(mOnJetEventListener, mHandler);
-        mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet));
+        assertTrue(mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet)));
         byte userID = 0;
         int segmentNum = 3;
         int libNum = -1;
         int repeatCount = 0;
         int transpose = 0;
         boolean[] muteFlags = new boolean[32];
-        assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum, repeatCount, transpose,
+        assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum,
+                repeatCount, transpose,
                 muteFlags, userID));
         assertTrue(mJetPlayer.play());
         for (int i = 0; i < muteFlags.length; i++) {
@@ -96,7 +101,8 @@
         muteFlags[8] = false;
         muteFlags[9] = false;
         muteFlags[10] = false;
-        assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum, repeatCount, transpose,
+        assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum,
+                repeatCount, transpose,
                 muteFlags, userID));
         Thread.sleep(20000);
         assertTrue(mJetPlayer.pause());
@@ -112,16 +118,19 @@
         int repeatCount = 1;
         int transpose = 0;
         int muteFlags = 0;
-        mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+        assertTrue(mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount,
+                transpose, muteFlags, userID));
 
         segmentNum = 6;
         repeatCount = 1;
         transpose = -1;
-        mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+        assertTrue(mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount,
+                transpose, muteFlags, userID));
 
         segmentNum = 7;
         transpose = 0;
-        mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+        assertTrue(mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount,
+                transpose, muteFlags, userID));
 
         for (int i = 0; i < 7; i++) {
             assertTrue(mJetPlayer.triggerClip(i));
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 813af0f2..71cbd61 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -600,6 +600,29 @@
         return actualMax;
     }
 
+    private boolean knownTypes(String type) {
+        return (type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC  ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3      ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB   ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB   ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3     ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC     ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG     ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM    ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS     ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW      ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS   ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC      ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263     ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC     ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2    ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4    ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8      ) ||
+            type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9      ));
+    }
+
     public void testGetMaxSupportedInstances() {
         final int MAX_INSTANCES = 32;
         StringBuilder xmlOverrides = new StringBuilder();
@@ -610,6 +633,10 @@
 
             String[] types = info.getSupportedTypes();
             for (int j = 0; j < types.length; ++j) {
+                if (!knownTypes(types[j])) {
+                    Log.d(TAG, "skipping unknown type " + types[j]);
+                    continue;
+                }
                 Log.d(TAG, "calling getCapabilitiesForType " + types[j]);
                 CodecCapabilities caps = info.getCapabilitiesForType(types[j]);
                 int max = caps.getMaxSupportedInstances();
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index f844b76..75a5a13 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.cts.util.MediaUtils;
+import android.hardware.Camera;
 import android.media.AudioManager;
 import android.media.MediaCodec;
 import android.media.MediaDataSource;
@@ -49,6 +50,7 @@
 import java.io.File;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.List;
 import java.util.StringTokenizer;
 import java.util.UUID;
 import java.util.Vector;
@@ -95,6 +97,10 @@
         }
     }
 
+    public void testonInputBufferFilledSigsegv() throws Exception {
+        testIfMediaServerDied(R.raw.on_input_buffer_filled_sigsegv);
+    }
+
     public void testFlacHeapOverflow() throws Exception {
         testIfMediaServerDied(R.raw.heap_oob_flac);
     }
@@ -105,6 +111,7 @@
             public boolean onError(MediaPlayer mp, int what, int extra) {
                 assertTrue(mp == mMediaPlayer);
                 assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+                Log.w(LOG_TAG, "onError " + what);
                 return false;
             }
         });
@@ -120,10 +127,17 @@
         AssetFileDescriptor afd = mResources.openRawResourceFd(res);
         mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
         afd.close();
-        mMediaPlayer.prepare();
-        mMediaPlayer.start();
-        mOnCompletionCalled.waitForSignal();
-        mMediaPlayer.release();
+        try {
+            mMediaPlayer.prepare();
+            mMediaPlayer.start();
+            if (!mOnCompletionCalled.waitForSignal(5000)) {
+                Log.w(LOG_TAG, "testIfMediaServerDied: Timed out waiting for Error/Completion");
+            }
+        } catch (Exception e) {
+            Log.w(LOG_TAG, "playback failed", e);
+        } finally {
+            mMediaPlayer.release();
+        }
     }
 
     // Bug 13652927
@@ -731,7 +745,7 @@
     public void testVideoSurfaceResetting() throws Exception {
         final int tolerance = 150;
         final int audioLatencyTolerance = 1000;  /* covers audio path latency variability */
-        final int seekPos = 5000;
+        final int seekPos = 4760;  // This is the I-frame position
 
         final CountDownLatch seekDone = new CountDownLatch(1);
 
@@ -753,7 +767,12 @@
         mMediaPlayer.setDisplay(getActivity().getSurfaceHolder2());
         int posAfter = mMediaPlayer.getCurrentPosition();
 
-        assertEquals(posAfter, posBefore, tolerance);
+        /* temporarily disable timestamp checking because MediaPlayer now seeks to I-frame
+         * position, instead of requested position. setDisplay invovles a seek operation
+         * internally.
+         */
+        // TODO: uncomment out line below when MediaPlayer can seek to requested position.
+        // assertEquals(posAfter, posBefore, tolerance);
         assertTrue(mMediaPlayer.isPlaying());
 
         Thread.sleep(SLEEP_TIME);
@@ -767,7 +786,8 @@
         posBefore = mMediaPlayer.getCurrentPosition();
         mMediaPlayer.setDisplay(null);
         posAfter = mMediaPlayer.getCurrentPosition();
-        assertEquals(posAfter, posBefore, tolerance);
+        // TODO: uncomment out line below when MediaPlayer can seek to requested position.
+        // assertEquals(posAfter, posBefore, tolerance);
         assertTrue(mMediaPlayer.isPlaying());
 
         Thread.sleep(SLEEP_TIME);
@@ -776,7 +796,8 @@
         mMediaPlayer.setDisplay(getActivity().getSurfaceHolder());
         posAfter = mMediaPlayer.getCurrentPosition();
 
-        assertEquals(posAfter, posBefore, tolerance);
+        // TODO: uncomment out line below when MediaPlayer can seek to requested position.
+        // assertEquals(posAfter, posBefore, tolerance);
         assertTrue(mMediaPlayer.isPlaying());
 
         Thread.sleep(SLEEP_TIME);
@@ -802,15 +823,34 @@
         return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
     }
 
+    private Camera mCamera;
     private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception {
-        final int width = RECORDED_VIDEO_WIDTH;
-        final int height = RECORDED_VIDEO_HEIGHT;
+        int width = RECORDED_VIDEO_WIDTH;
+        int height = RECORDED_VIDEO_HEIGHT;
         final String file = RECORDED_FILE;
         final long durationMs = RECORDED_DURATION_MS;
 
         if (!hasCamera()) {
             return;
         }
+
+        boolean isSupported = false;
+        mCamera = Camera.open(0);
+        Camera.Parameters parameters = mCamera.getParameters();
+        List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
+        for (Camera.Size size : previewSizes)
+        {
+            if (size.width == width && size.height == height) {
+                isSupported = true;
+                break;
+            }
+        }
+        mCamera.release();
+        mCamera = null;
+        if (!isSupported) {
+            width = previewSizes.get(0).width;
+            height = previewSizes.get(0).height;
+        }
         checkOrientation(angle);
         recordVideo(width, height, angle, file, durationMs);
         checkDisplayedVideoSize(width, height, angle, file);
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index f7b6c91..4c90e56 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -60,6 +60,8 @@
     private static final int RECORDED_DUR_TOLERANCE_MS = 1000;
     private static final int VIDEO_WIDTH = 176;
     private static final int VIDEO_HEIGHT = 144;
+    private static int mVideoWidth = VIDEO_WIDTH;
+    private static int mVideoHeight = VIDEO_HEIGHT;
     private static final int VIDEO_BIT_RATE_IN_BPS = 128000;
     private static final double VIDEO_TIMELAPSE_CAPTURE_RATE_FPS = 1.0;
     private static final int AUDIO_BIT_RATE_IN_BPS = 12200;
@@ -219,6 +221,7 @@
         int durMs = timelapse? RECORD_TIME_LAPSE_MS: RECORD_TIME_MS;
         for (int cameraId = 0; cameraId < nCamera; cameraId++) {
             mCamera = Camera.open(cameraId);
+            setSupportedResolution(mCamera);
             recordVideoUsingCamera(mCamera, OUTPUT_PATH, durMs, timelapse);
             mCamera.release();
             mCamera = null;
@@ -226,6 +229,21 @@
         }
     }
 
+    private void setSupportedResolution(Camera camera) {
+        Camera.Parameters parameters = camera.getParameters();
+        List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
+        for (Camera.Size size : previewSizes)
+        {
+            if (size.width == VIDEO_WIDTH && size.height == VIDEO_HEIGHT) {
+                mVideoWidth = VIDEO_WIDTH;
+                mVideoHeight = VIDEO_HEIGHT;
+                return;
+            }
+        }
+        mVideoWidth = previewSizes.get(0).width;
+        mVideoHeight = previewSizes.get(0).height;
+    }
+
     private void recordVideoUsingCamera(
             Camera camera, String fileName, int durMs, boolean timelapse) throws Exception {
         // FIXME:
@@ -242,7 +260,7 @@
         mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
         mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
         mMediaRecorder.setVideoFrameRate(frameRate);
-        mMediaRecorder.setVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT);
+        mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
         mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
         mMediaRecorder.setOutputFile(fileName);
         mMediaRecorder.setLocation(LATITUDE, LONGITUDE);
@@ -872,6 +890,12 @@
         boolean success = false;
         Surface surface = null;
         int noOfFailure = 0;
+
+        if (!hasH264()) {
+            MediaUtils.skipTest("no codecs");
+            return true;
+        }
+
         try {
             if (persistent) {
                 surface = MediaCodec.createPersistentInputSurface();
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 7497da2..ce61d76 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -312,6 +312,11 @@
     }
 
     public void testPlayHlsStreamWithTimedId3() throws Throwable {
+        if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
+            Log.d(TAG, "Device doesn't have video codec, skipping test");
+            return;
+        }
+
         mServer = new CtsTestServer(mContext);
         try {
             // counter must be final if we want to access it inside onTimedMetaData;
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index e3d2f09..fb1521d 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -174,6 +174,7 @@
         private boolean mSignaledDecoderEOS;
 
         protected boolean mCompleted;
+        protected boolean mEncoderIsActive;
         protected boolean mEncodeOutputFormatUpdated;
         protected final Object mCondition = new Object();
 
@@ -322,6 +323,10 @@
                         mCompleted = true;
                         mCondition.notifyAll(); // condition is always satisfied
                     }
+                } else {
+                    synchronized(mCondition) {
+                        mEncoderIsActive = true;
+                    }
                 }
             }
         }
@@ -395,6 +400,11 @@
                             break;
                         }
                         if (!haveBuffers()) {
+                            if (mEncoderIsActive) {
+                                mEncoderIsActive = false;
+                                Log.d(TAG, "No more input but still getting output from encoder.");
+                                continue;
+                            }
                             fail("timed out after " + mBuffersToRender.size()
                                     + " decoder output and " + mEncInputBuffers.size()
                                     + " encoder input buffers");
@@ -557,7 +567,6 @@
             implements SurfaceTexture.OnFrameAvailableListener {
         private static final String TAG = "SurfaceVideoProcessor";
         private boolean mFrameAvailable;
-        private boolean mEncoderIsActive;
         private boolean mGotDecoderEOS;
         private boolean mSignaledEncoderEOS;
 
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 88dbd7c..9a99c22 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,6 +16,9 @@
 
 package android.net.cts;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -23,6 +26,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkConfig;
@@ -467,4 +471,23 @@
             mAvailableLatch.countDown();
         }
     }
+
+    /** Verify restricted networks cannot be requested. */
+    public void testRestrictedNetworks() {
+        // Verify we can request unrestricted networks:
+        NetworkRequest request = new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_INTERNET).build();
+        NetworkCallback callback = new NetworkCallback();
+        mCm.requestNetwork(request, callback);
+        mCm.unregisterNetworkCallback(callback);
+        // Verify we cannot request restricted networks:
+        request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build();
+        callback = new NetworkCallback();
+        try {
+            mCm.requestNetwork(request, callback);
+            fail("No exception thrown when restricted network requested.");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+    }
 }
diff --git a/tests/tests/os/jni/seccomp_sample_program.cpp b/tests/tests/os/jni/seccomp_sample_program.cpp
index 3c90196..3bc7da4 100644
--- a/tests/tests/os/jni/seccomp_sample_program.cpp
+++ b/tests/tests/os/jni/seccomp_sample_program.cpp
@@ -826,7 +826,7 @@
   {0x35, 0, 4, 0x76},
   {0x35, 0, 2, 0x79},
   {0x35, 0, 241, 0x7a},
-  {0x35, 240, 239, 0x7b},
+  {0x35, 240, 239, 0x7c},
   {0x35, 238, 239, 0x77},
   {0x35, 0, 2, 0x72},
   {0x35, 0, 236, 0x73},
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 419f320..af60139 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -29,8 +29,8 @@
 
     private static final String LOG_TAG = "BuildVersionTest";
     private static final Set<String> EXPECTED_RELEASES =
-            new HashSet<String>(Arrays.asList("5.1", "5.1.1"));
-    private static final int EXPECTED_SDK = 22;
+            new HashSet<String>(Arrays.asList("6.0"));
+    private static final int EXPECTED_SDK = 23;
     private static final String EXPECTED_BUILD_VARIANT = "user";
     private static final String EXPECTED_TAG = "release-keys";
 
diff --git a/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java b/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java
index 0b389a4..d8e128b 100644
--- a/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java
+++ b/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java
@@ -82,8 +82,8 @@
     }
 
     private static final String[] armv8RequiredFeatures = {
-            "wp", "half", "thumb", "fastmult", "vfp", "edsp", "neon",
-            "vfpv3", "tlsi", "vfpv4", "idiva", "idivt" };
+            "half", "thumb", "fastmult", "vfp", "edsp", "neon",
+            "vfpv3", "vfpv4", "idiva", "idivt" };
 
     private static void assertInCpuinfo(List<String> features,
             String feature) {
diff --git a/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
index 8714100..a95c96e 100644
--- a/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
@@ -53,21 +53,4 @@
             // expected
         }
     }
-
-    /**
-     * Verify that calling {@link ConnectivityManager#requestRouteToHost(int, int)}
-     * requires permissions.
-     * <p>Tests Permission:
-     *   {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
-     */
-    @SmallTest
-    public void testRequestRouteToHost() {
-        try {
-            mConnectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE, 1);
-            fail("Was able to call requestRouteToHost");
-        } catch (SecurityException e) {
-            // expected
-        }
-    }
 }
-
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index cf6a09d..0962bbd 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -251,7 +251,6 @@
     @MediumTest
     public void testProcSelfOomAdjSane() {
         File f = new File("/proc/self/oom_adj");
-        assertTrue(f.canRead());
         assertFalse(f.canWrite());
         assertFalse(f.canExecute());
     }
@@ -259,7 +258,6 @@
     @MediumTest
     public void testProcSelfOomScoreAdjSane() {
         File f = new File("/proc/self/oom_score_adj");
-        assertTrue(f.canRead());
         assertFalse(f.canWrite());
         assertFalse(f.canExecute());
     }
diff --git a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
index f7e5443..c260706 100644
--- a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
@@ -98,4 +98,4 @@
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index e75ec94..1378bdb 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -140,6 +140,11 @@
 
     @Override
     public void setUp() throws Exception {
+        super.setUp();
+        if (!supportsPrinting()) {
+            return;
+        }
+
         // Make sure we start with a clean slate.
         clearPrintSpoolerData();
         enablePrintServices();
@@ -176,23 +181,26 @@
 
     @Override
     public void tearDown() throws Exception {
-        // Done with the activity.
-        getActivity().finish();
-        enableImes();
+        if (supportsPrinting()) {
+            // Done with the activity.
+            getActivity().finish();
+            enableImes();
 
-        // Restore the locale if needed.
-        if (mOldLocale != null) {
-            Resources resources = getInstrumentation().getTargetContext().getResources();
-            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
-            Configuration newConfiguration = new Configuration(resources.getConfiguration());
-            newConfiguration.locale = mOldLocale;
-            mOldLocale = null;
-            resources.updateConfiguration(newConfiguration, displayMetrics);
+            // Restore the locale if needed.
+            if (mOldLocale != null) {
+                Resources resources = getInstrumentation().getTargetContext().getResources();
+                DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+                Configuration newConfiguration = new Configuration(resources.getConfiguration());
+                newConfiguration.locale = mOldLocale;
+                mOldLocale = null;
+                resources.updateConfiguration(newConfiguration, displayMetrics);
+            }
+
+            disablePrintServices();
+            // Make sure the spooler is cleaned.
+            clearPrintSpoolerData();
         }
-
-        disablePrintServices();
-        // Make sure the spooler is cleaned.
-        clearPrintSpoolerData();
+        super.tearDown();
     }
 
     protected void print(final PrintDocumentAdapter adapter) {
diff --git a/tests/tests/netlegacy22/Android.mk b/tests/tests/systemui/Android.mk
similarity index 63%
copy from tests/tests/netlegacy22/Android.mk
copy to tests/tests/systemui/Android.mk
index 3174652..1a15fd2 100644
--- a/tests/tests/netlegacy22/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -12,5 +12,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Build the API tests and the permissions tests using their own makefiles.
-include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSystemUiTestCases
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
new file mode 100644
index 0000000..bf5df5b
--- /dev/null
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.systemui">
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application>
+        <activity android:name=".LightStatusBarActivity"
+                android:theme="@android:style/Theme.Material.NoActionBar"></activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.systemui">
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java b/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
new file mode 100644
index 0000000..626a179
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.systemui;
+
+/**
+ * Copies of non-public {@link android.graphics.Color} APIs
+ */
+public class ColorUtils {
+
+    public static float brightness(int argb) {
+        int r = (argb >> 16) & 0xFF;
+        int g = (argb >> 8) & 0xFF;
+        int b = argb & 0xFF;
+
+        int V = Math.max(b, Math.max(r, g));
+
+        return (V / 255.f);
+    }
+
+    public static float hue(int argb) {
+        int r = (argb >> 16) & 0xFF;
+        int g = (argb >> 8) & 0xFF;
+        int b = argb & 0xFF;
+
+        int V = Math.max(b, Math.max(r, g));
+        int temp = Math.min(b, Math.min(r, g));
+
+        float H;
+
+        if (V == temp) {
+            H = 0;
+        } else {
+            final float vtemp = (float) (V - temp);
+            final float cr = (V - r) / vtemp;
+            final float cg = (V - g) / vtemp;
+            final float cb = (V - b) / vtemp;
+
+            if (r == V) {
+                H = cb - cg;
+            } else if (g == V) {
+                H = 2 + cr - cb;
+            } else {
+                H = 4 + cg - cr;
+            }
+
+            H /= 6.f;
+            if (H < 0) {
+                H++;
+            }
+        }
+
+        return H;
+    }
+}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
new file mode 100644
index 0000000..3722320
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.cts.systemui;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+
+/**
+ * An activity that exercises SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ */
+public class LightStatusBarActivity extends Activity {
+
+    private View mContent;
+
+    public void onCreate(Bundle bundle){
+        super.onCreate(bundle);
+
+        mContent = new View(this);
+        mContent.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+        setContentView(mContent);
+    }
+
+    public void setLightStatusBar(boolean lightStatusBar) {
+        int vis = getWindow().getDecorView().getSystemUiVisibility();
+        if (lightStatusBar) {
+            vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        } else {
+            vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        }
+        getWindow().getDecorView().setSystemUiVisibility(vis);
+    }
+
+    public int getTop() {
+        return mContent.getLocationOnScreen()[1];
+    }
+
+    public int getWidth() {
+        return mContent.getWidth();
+    }
+}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
new file mode 100644
index 0000000..b5bfd51
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.systemui;
+
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Test for light status bar.
+ */
+public class LightStatusBarTests extends ActivityInstrumentationTestCase2<LightStatusBarActivity> {
+
+    public static final String TAG = "LightStatusBarTests";
+
+    public static final String DUMP_PATH = "/sdcard/lightstatustest.png";
+
+    public LightStatusBarTests() {
+        super(LightStatusBarActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // As the way to access Instrumentation is changed in the new runner, we need to inject it
+        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+        // be marked as deprecated and replaced with ActivityTestRule.
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+    }
+
+    public void testLightStatusBarIcons() throws Throwable {
+        PackageManager pm = getInstrumentation().getContext().getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            // No status bar on TVs and watches.
+            return;
+        }
+
+        if (!ActivityManager.isHighEndGfx()) {
+            // non-highEndGfx devices don't do colored system bars.
+            return;
+        }
+
+        requestLightStatusBar(Color.RED /* background */);
+        Thread.sleep(1000);
+
+        Bitmap bitmap = takeStatusBarScreenshot();
+        Stats s = evaluateLightStatusBarBitmap(bitmap, Color.RED /* background */);
+        boolean success = false;
+
+        try {
+            assertMoreThan("Not enough background pixels", 0.3f,
+                    (float) s.backgroundPixels / s.totalPixels(),
+                    "Is the status bar background showing correctly (solid red)?");
+
+            assertMoreThan("Not enough pixels colored as in the spec", 0.1f,
+                    (float) s.iconPixels / s.foregroundPixels(),
+                    "Are the status bar icons colored according to the spec "
+                            + "(60% black and 24% black)?");
+
+            assertLessThan("Too many lighter pixels lighter than the background", 0.05f,
+                    (float) s.sameHueLightPixels / s.foregroundPixels(),
+                    "Are the status bar icons dark?");
+
+            assertLessThan("Too many pixels with a changed hue", 0.05f,
+                    (float) s.unexpectedHuePixels / s.foregroundPixels(),
+                    "Are the status bar icons color-free?");
+
+            success = true;
+        } finally {
+            if (!success) {
+                Log.e(TAG, "Dumping failed bitmap to " + DUMP_PATH);
+                dumpBitmap(bitmap);
+            }
+        }
+    }
+
+    private void assertMoreThan(String what, float expected, float actual, String hint) {
+        if (!(actual > expected)) {
+            fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void assertLessThan(String what, float expected, float actual, String hint) {
+        if (!(actual < expected)) {
+            fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void requestLightStatusBar(final int background) throws Throwable {
+        final LightStatusBarActivity activity = getActivity();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.getWindow().setStatusBarColor(background);
+                activity.setLightStatusBar(true);
+            }
+        });
+    }
+
+    private static class Stats {
+        int backgroundPixels;
+        int iconPixels;
+        int sameHueDarkPixels;
+        int sameHueLightPixels;
+        int unexpectedHuePixels;
+
+        int totalPixels() {
+            return backgroundPixels + iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        int foregroundPixels() {
+            return iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("{bg=%d, ic=%d, dark=%d, light=%d, bad=%d}",
+                    backgroundPixels, iconPixels, sameHueDarkPixels, sameHueLightPixels,
+                    unexpectedHuePixels);
+        }
+    }
+
+    private Stats evaluateLightStatusBarBitmap(Bitmap bitmap, int background) {
+        int iconColor = 0x99000000;
+        int iconPartialColor = 0x3d000000;
+
+        int mixedIconColor = mixSrcOver(background, iconColor);
+        int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
+
+        int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
+        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+        Stats s = new Stats();
+        float eps = 0.005f;
+
+        for (int c : pixels) {
+            if (c == background) {
+                s.backgroundPixels++;
+                continue;
+            }
+
+            // What we expect the icons to be colored according to the spec.
+            if (c == mixedIconColor || c == mixedIconPartialColor) {
+                s.iconPixels++;
+                continue;
+            }
+
+            // Due to anti-aliasing, there will be deviations from the ideal icon color, but it
+            // should still be mostly the same hue.
+            float hueDiff = Math.abs(ColorUtils.hue(background) - ColorUtils.hue(c));
+            if (hueDiff < eps || hueDiff > 1 - eps) {
+                // .. it shouldn't be lighter than the original background though.
+                if (ColorUtils.brightness(c) > ColorUtils.brightness(background)) {
+                    s.sameHueLightPixels++;
+                } else {
+                    s.sameHueDarkPixels++;
+                }
+                continue;
+            }
+
+            s.unexpectedHuePixels++;
+        }
+
+        return s;
+    }
+
+    private void dumpBitmap(Bitmap bitmap) {
+        FileOutputStream fileStream = null;
+        try {
+            fileStream = new FileOutputStream(DUMP_PATH);
+            bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
+            fileStream.flush();
+        } catch (Exception e) {
+            Log.e(TAG, "Dumping bitmap failed.", e);
+        } finally {
+            if (fileStream != null) {
+                try {
+                    fileStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private int mixSrcOver(int background, int foreground) {
+        int bgAlpha = Color.alpha(background);
+        int bgRed = Color.red(background);
+        int bgGreen = Color.green(background);
+        int bgBlue = Color.blue(background);
+
+        int fgAlpha = Color.alpha(foreground);
+        int fgRed = Color.red(foreground);
+        int fgGreen = Color.green(foreground);
+        int fgBlue = Color.blue(foreground);
+
+        return Color.argb(fgAlpha + (255 - fgAlpha) * bgAlpha / 255,
+                    fgRed + (255 - fgAlpha) * bgRed / 255,
+                    fgGreen + (255 - fgAlpha) * bgGreen / 255,
+                    fgBlue + (255 - fgAlpha) * bgBlue / 255);
+    }
+
+    private Bitmap takeStatusBarScreenshot() {
+        Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
+        return Bitmap.createBitmap(fullBitmap, 0, 0,
+                getActivity().getWidth(), getActivity().getTop());
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java b/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java
index 00a56ac..3a0dbd3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java
@@ -52,17 +52,20 @@
     @Override
     protected void tearDown() throws Exception {
         if (mShouldTestTelecom) {
-            tearDownConnectionServices(TEST_PHONE_ACCOUNT_HANDLE, TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
+            tearDownRemoteConnectionService(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
         }
         super.tearDown();
     }
 
     protected void setupConnectionServices(MockConnectionService connectionService,
-            MockConnectionService remoteConnectionService, int flags)
-            throws Exception {
+            MockConnectionService remoteConnectionService, int flags) throws Exception {
         // Setup the primary connection service first
         setupConnectionService(connectionService, flags);
+        setupRemoteConnectionService(remoteConnectionService, flags);
+    }
 
+    protected void setupRemoteConnectionService(MockConnectionService remoteConnectionService,
+            int flags) throws Exception {
         if (remoteConnectionService != null) {
             this.remoteConnectionService = remoteConnectionService;
         } else {
@@ -78,19 +81,23 @@
                     TEST_REMOTE_PHONE_ACCOUNT_HANDLE,
                     REMOTE_ACCOUNT_LABEL,
                     TEST_REMOTE_PHONE_ACCOUNT_ADDRESS);
+            // Wait till the adb commands have executed and account is in Telecom database.
+            assertPhoneAccountRegistered(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
         }
         if ((flags & FLAG_ENABLE) != 0) {
             TestUtils.enablePhoneAccount(getInstrumentation(), TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
+            // Wait till the adb commands have executed and account is enabled in Telecom database.
+            assertPhoneAccountEnabled(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
         }
     }
 
-    protected void tearDownConnectionServices(PhoneAccountHandle accountHandle,
-            PhoneAccountHandle remoteAccountHandle) throws Exception {
-        // Teardown the primary connection service first
-        tearDownConnectionService(accountHandle);
-
+    protected void tearDownRemoteConnectionService(PhoneAccountHandle remoteAccountHandle)
+            throws Exception {
+        assertNumConnections(this.remoteConnectionService, 0);
         mTelecomManager.unregisterPhoneAccount(remoteAccountHandle);
         CtsRemoteConnectionService.tearDown();
+        //Telecom doesn't unbind the remote connection service at the end of all calls today.
+        //assertCtsRemoteConnectionServiceUnbound();
         this.remoteConnectionService = null;
     }
 
@@ -210,4 +217,22 @@
                 "Remote Conference should be in state " + state
         );
     }
+
+    void assertCtsRemoteConnectionServiceUnbound() {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected(){
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return CtsRemoteConnectionService.isServiceUnbound();
+                    }
+                },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "CtsRemoteConnectionService not yet unbound!"
+        );
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 31ca09b..d7fe239 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -110,13 +110,13 @@
                 TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
             }
             tearDownConnectionService(TEST_PHONE_ACCOUNT_HANDLE);
+            assertMockInCallServiceUnbound();
         }
         super.tearDown();
     }
 
     protected PhoneAccount setupConnectionService(MockConnectionService connectionService,
-            int flags)
-            throws Exception {
+            int flags) throws Exception {
         if (connectionService != null) {
             this.connectionService = connectionService;
         } else {
@@ -130,14 +130,18 @@
         }
         if ((flags & FLAG_ENABLE) != 0) {
             TestUtils.enablePhoneAccount(getInstrumentation(), TEST_PHONE_ACCOUNT_HANDLE);
+            // Wait till the adb commands have executed and account is enabled in Telecom database.
+            assertPhoneAccountEnabled(TEST_PHONE_ACCOUNT_HANDLE);
         }
 
         return TEST_PHONE_ACCOUNT;
     }
 
     protected void tearDownConnectionService(PhoneAccountHandle accountHandle) throws Exception {
+        assertNumConnections(this.connectionService, 0);
         mTelecomManager.unregisterPhoneAccount(accountHandle);
         CtsConnectionService.tearDown();
+        assertCtsConnectionServiceUnbound();
         this.connectionService = null;
     }
 
@@ -513,6 +517,22 @@
     }
 
 
+    void assertNumConnections(final MockConnectionService connService, final int numConnections) {
+        waitUntilConditionIsTrueOrTimeout(new Condition() {
+                                              @Override
+                                              public Object expected() {
+                                                  return numConnections;
+                                              }
+                                              @Override
+                                              public Object actual() {
+                                                  return connService.getAllConnections().size();
+                                              }
+                                          },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "ConnectionService should contain " + numConnections + " connections."
+        );
+    }
+
     void assertMuteState(final InCallService incallService, final boolean isMuted) {
         waitUntilConditionIsTrueOrTimeout(
                 new Condition() {
@@ -621,7 +641,7 @@
                     }
                 },
                 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
-                "Call should be in state " + state
+                "Call: " + call + " should be in state " + state
         );
     }
 
@@ -731,6 +751,79 @@
         );
     }
 
+    void assertPhoneAccountRegistered(final PhoneAccountHandle handle) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return mTelecomManager.getPhoneAccount(handle) != null;
+                    }
+                },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Phone account registration failed for " + handle
+        );
+    }
+
+    void assertPhoneAccountEnabled(final PhoneAccountHandle handle) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle);
+                        return (phoneAccount != null && phoneAccount.isEnabled());
+                    }
+                },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Phone account enable failed for " + handle
+        );
+    }
+
+    void assertCtsConnectionServiceUnbound() {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return CtsConnectionService.isServiceUnbound();
+                    }
+                },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "CtsConnectionService not yet unbound!"
+        );
+    }
+
+    void assertMockInCallServiceUnbound() {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return MockInCallService.isServiceUnbound();
+                    }
+                },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "MockInCallService not yet unbound!"
+        );
+    }
+
     void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout,
             String description) {
         final long start = System.currentTimeMillis();
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index 121d559..508870c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -50,7 +50,6 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mContext = getInstrumentation().getContext();
         if (mShouldTestTelecom) {
             addOutgoingCalls();
             addConferenceCall(mCall1, mCall2);
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index afaa3eb..836ca48 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -48,20 +48,13 @@
         placeAndVerifyCall();
         verifyConnectionForOutgoingCall();
 
+        // Add second connection (add existing connection)
         final MockConnection connection = new MockConnection();
         connection.setOnHold();
         CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
-
-        try {
-            if (!mInCallCallbacks.lock.tryAcquire(3, TimeUnit.SECONDS)) {
-                fail("No call added to InCallService.");
-            }
-        } catch (InterruptedException e) {
-            Log.i(TAG, "Test interrupted!");
-        }
-
-        final MockInCallService inCallService = mInCallCallbacks.getService();
-        final Call call = inCallService.getLastCall();
+        assertNumCalls(mInCallCallbacks.getService(), 2);
+        mInCallCallbacks.lock.drainPermits();
+        final Call call = mInCallCallbacks.getService().getLastCall();
         assertCallState(call, Call.STATE_HOLDING);
     }
 
@@ -77,17 +70,22 @@
         Collection<Connection> connections = CtsConnectionService.getAllConnectionsFromTelecom();
         assertEquals(1, connections.size());
         assertTrue(connections.contains(connection1));
+        // Need to move this to active since we reject the 3rd incoming call below if this is in
+        // dialing state (b/23428950).
+        connection1.setActive();
+        assertCallState(mInCallCallbacks.getService().getLastCall(), Call.STATE_ACTIVE);
 
         // Add second connection (add existing connection)
         final Connection connection2 = new MockConnection();
         CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection2);
-
+        assertNumCalls(mInCallCallbacks.getService(), 2);
+        mInCallCallbacks.lock.drainPermits();
         connections = CtsConnectionService.getAllConnectionsFromTelecom();
         assertEquals(2, connections.size());
         assertTrue(connections.contains(connection2));
 
         // Add third connection (incoming call)
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         final Connection connection3 = verifyConnectionForIncomingCall();
         connections = CtsConnectionService.getAllConnectionsFromTelecom();
         assertEquals(3, connections.size());
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index 3c30e6b..d8d5773 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -16,6 +16,9 @@
 
 package android.telecom.cts;
 
+import static org.junit.Assert.assertFalse;
+
+import android.content.Intent;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
@@ -23,6 +26,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.RemoteConference;
 import android.telecom.RemoteConnection;
+import android.util.Log;
 
 import java.util.Collection;
 
@@ -43,10 +47,12 @@
  *
  */
 public class CtsConnectionService extends ConnectionService {
+    private static String LOG_TAG = "CtsConnectionService";
     // This is the connection service implemented by the test
     private static ConnectionService sConnectionService;
     // This is the connection service registered with Telecom
     private static ConnectionService sTelecomConnectionService;
+    private static boolean mIsServiceUnbound;
 
     public CtsConnectionService() throws Exception {
         super();
@@ -65,13 +71,14 @@
     private static Object sLock = new Object();
 
     public static void setUp(PhoneAccountHandle phoneAccountHandle,
-            ConnectionService connectionService)
-            throws Exception {
+            ConnectionService connectionService) throws Exception {
         synchronized(sLock) {
             if (sConnectionService != null) {
                 throw new Exception("Mock ConnectionService exists.  Failed to call tearDown().");
             }
             sConnectionService = connectionService;
+            // Cant override the onBind method for ConnectionService, so reset it here.
+            mIsServiceUnbound = false;
         }
     }
 
@@ -178,4 +185,16 @@
             }
         }
     }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.i(LOG_TAG, "Service unbounded");
+        assertFalse(mIsServiceUnbound);
+        mIsServiceUnbound = true;
+        return super.onUnbind(intent);
+    }
+
+    public static boolean isServiceUnbound() {
+        return mIsServiceUnbound;
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java
index 3738487..13b525f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java
@@ -16,11 +16,15 @@
 
 package android.telecom.cts;
 
+import static org.junit.Assert.assertFalse;
+
+import android.content.Intent;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
 import android.telecom.ConnectionService;
 import android.telecom.PhoneAccountHandle;
+import android.util.Log;
 
 /**
  * This is the Remote ConnectionService for Telecom's CTS App. Since telecom requires that a
@@ -39,10 +43,12 @@
  *
  */
 public class CtsRemoteConnectionService extends ConnectionService {
+    private static String LOG_TAG = "CtsConnectionService";
     // This is the connection service implemented by the test
     private static ConnectionService sConnectionService;
     // This is the connection service registered with Telecom
     private static ConnectionService sTelecomConnectionService;
+    private static boolean mIsServiceUnbound;
 
     public CtsRemoteConnectionService() throws Exception {
         super();
@@ -64,13 +70,14 @@
     private static Object sLock = new Object();
 
     public static void setUp(PhoneAccountHandle phoneAccountHandle,
-            ConnectionService connectionService)
-            throws Exception {
+            ConnectionService connectionService) throws Exception {
         synchronized(sLock) {
             if (sConnectionService != null) {
                 throw new Exception("Mock ConnectionService exists.  Failed to call tearDown().");
             }
             sConnectionService = connectionService;
+            // Cant override the onBind method for ConnectionService, so reset it here.
+            mIsServiceUnbound = false;
         }
     }
 
@@ -124,4 +131,16 @@
             sTelecomConnectionService.addConference(conference);
         }
     }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.i(LOG_TAG, "Service unbounded");
+        assertFalse(mIsServiceUnbound);
+        mIsServiceUnbound = true;
+        return super.onUnbind(intent);
+    }
+
+    public static boolean isServiceUnbound() {
+        return mIsServiceUnbound;
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 19d27af..02d2f15 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -188,7 +188,7 @@
             return;
         }
 
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -209,7 +209,7 @@
             return;
         }
 
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -232,7 +232,7 @@
             return;
         }
 
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
         final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -390,7 +390,7 @@
             return;
         }
 
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         verifyConnectionForIncomingCall();
         final MockInCallService inCallService = mInCallCallbacks.getService();
 
@@ -428,7 +428,7 @@
         assertEquals("InCallService.getCalls() should return list with 1 call.", 1, calls.size());
         assertEquals(call1, calls.get(0));
 
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         verifyConnectionForIncomingCall();
 
         final Call call2 = inCallService.getLastCall();
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index d556baa..9bb83a1 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -66,6 +66,7 @@
         if (mRemoteConnection != null) {
             mRemoteConnection.reject();
         }
+        destroy();
     }
 
     @Override
@@ -90,18 +91,20 @@
     public void onDisconnect() {
         super.onDisconnect();
         setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
-        destroy();
         if (mRemoteConnection != null) {
             mRemoteConnection.disconnect();
         }
+        destroy();
     }
 
     @Override
     public void onAbort() {
         super.onAbort();
+        setDisconnected(new DisconnectCause(DisconnectCause.UNKNOWN));
         if (mRemoteConnection != null) {
             mRemoteConnection.abort();
         }
+        destroy();
     }
 
     @Override
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
index 1856603..0f1f538 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
@@ -16,10 +16,14 @@
 
 package android.telecom.cts;
 
+import static org.junit.Assert.assertFalse;
+
+import android.content.Intent;
 import android.telecom.Call;
 import android.telecom.CallAudioState;
 import android.telecom.InCallService;
 import android.util.ArrayMap;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,6 +31,7 @@
 import java.util.concurrent.Semaphore;
 
 public class MockInCallService extends InCallService {
+    private static String LOG_TAG = "MockInCallService";
     private ArrayList<Call> mCalls = new ArrayList<>();
     private ArrayList<Call> mConferenceCalls = new ArrayList<>();
     private static InCallServiceCallbacks sCallbacks;
@@ -34,6 +39,7 @@
             new ArrayMap<Call, MockVideoCallCallback>();
 
     private static final Object sLock = new Object();
+    private static boolean mIsServiceUnbound;
 
     public static abstract class InCallServiceCallbacks {
         private MockInCallService mService;
@@ -152,9 +158,11 @@
 
     @Override
     public android.os.IBinder onBind(android.content.Intent intent) {
+        Log.i(LOG_TAG, "Service bounded");
         if (getCallbacks() != null) {
             getCallbacks().setService(this);
         }
+        mIsServiceUnbound = false;
         return super.onBind(intent);
     }
 
@@ -312,4 +320,16 @@
     public MockVideoCallCallback getVideoCallCallback(Call call) {
         return mVideoCallCallbacks.get(call);
     }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.i(LOG_TAG, "Service unbounded");
+        assertFalse(mIsServiceUnbound);
+        mIsServiceUnbound = true;
+        return super.onUnbind(intent);
+    }
+
+    public static boolean isServiceUnbound() {
+        return mIsServiceUnbound;
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java b/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
index 8ffcf48..e95a290 100644
--- a/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
@@ -62,7 +62,5 @@
             res.wait(CS_WAIT_MILLIS);
         }
         assertEquals(address, res[0]);
-
-        tearDownConnectionService(account.getAccountHandle());
     }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
index f2422c9..bba9a44 100644
--- a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
@@ -18,6 +18,8 @@
 
 import static android.telecom.cts.TestUtils.shouldTestTelecom;
 
+import android.content.Context;
+import android.media.AudioManager;
 import android.os.Bundle;
 import android.telecom.CallAudioState;
 import android.telecom.TelecomManager;
@@ -35,15 +37,13 @@
         }
     }
 
-    // TODO: Need to send some commands to the UserManager via adb to do setup
+    /* TODO: Need to send some commands to the UserManager via adb to do setup
     public void testDisallowOutgoingCallsForSecondaryUser() {
+    } */
 
-    }
-
-    // TODO: Need to figure out a way to mock emergency calls without adb root
+    /* TODO: Need to figure out a way to mock emergency calls without adb root
     public void testOutgoingCallBroadcast_isSentForAllCalls() {
-
-    }
+    } */
 
     /**
      * Verifies that providing the EXTRA_START_CALL_WITH_SPEAKERPHONE extra starts the call with
@@ -68,11 +68,15 @@
             return;
         }
 
+        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        int expectedRoute = am.isWiredHeadsetOn() ?
+                CallAudioState.ROUTE_WIRED_HEADSET : CallAudioState.ROUTE_EARPIECE;
+
         final Bundle extras = new Bundle();
         extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
         placeAndVerifyCall(extras);
         verifyConnectionForOutgoingCall();
-        assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
+        assertAudioRoute(mInCallCallbacks.getService(), expectedRoute);
     }
 
     public void testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault() {
@@ -80,8 +84,12 @@
             return;
         }
 
+        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        int expectedRoute = am.isWiredHeadsetOn() ?
+                CallAudioState.ROUTE_WIRED_HEADSET : CallAudioState.ROUTE_EARPIECE;
+
         placeAndVerifyCall();
         verifyConnectionForOutgoingCall();
-        assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
+        assertAudioRoute(mInCallCallbacks.getService(), expectedRoute);
     }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
index 3fc65ea..787966a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
@@ -61,7 +61,6 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mContext = getInstrumentation().getContext();
         if (mShouldTestTelecom) {
             addRemoteConferenceCall();
             verifyRemoteConferenceObject(mRemoteConferenceObject, mRemoteConference, mConference);
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
index 79fb592..5b552a0 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
@@ -1210,7 +1210,6 @@
         };
         mRemoteConnectionObject.registerCallback(callback, handler);
         mRemoteConnection.createMockVideoProvider();
-        mRemoteConnection.setVideoProvider(mRemoteConnection.getMockVideoProvider());
         callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
         assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
         mRemoteConnectionObject.unregisterCallback(callback);
diff --git a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
index 466a90b..e7130ba 100644
--- a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
@@ -35,21 +35,12 @@
         }
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        if (mInCallCallbacks != null && mInCallCallbacks.getService() != null) {
-            mInCallCallbacks.getService().disconnectLastCall();
-            assertNumCalls(mInCallCallbacks.getService(), 0);
-        }
-        super.tearDown();
-    }
-
     public void testIncomingCallShortPress_acceptsCall() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
 
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
         final Call call = mInCallCallbacks.getService().getLastCall();
@@ -66,7 +57,7 @@
             return;
         }
 
-        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
         final Call call = mInCallCallbacks.getService().getLastCall();
@@ -119,16 +110,6 @@
         assertConnectionState(connection, Connection.STATE_DISCONNECTED);
     }
 
-    public void testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault() {
-        if (!mShouldTestTelecom) {
-            return;
-        }
-
-        placeAndVerifyCall();
-        verifyConnectionForOutgoingCall();
-        assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
-    }
-
     private void sendMediaButtonShortPress() throws Exception {
         sendMediaButtonPress(false /* longPress */);
     }
diff --git a/tests/tests/telephony/src/android/telephony/cts/MmsTest.java b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
index 176c50c..e15b45f 100644
--- a/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.SystemClock;
 import android.telephony.SmsManager;
@@ -84,6 +85,7 @@
     private Random mRandom;
     private SentReceiver mSentReceiver;
     private TelephonyManager mTelephonyManager;
+    private PackageManager mPackageManager;
 
     private static class SentReceiver extends BroadcastReceiver {
         private final Object mLock;
@@ -164,15 +166,26 @@
         mRandom = new Random();
         mTelephonyManager =
                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        mPackageManager = mContext.getPackageManager();
     }
 
     public void testSendMmsMessage() {
-        if (!mTelephonyManager.isSmsCapable()) {
-            Log.i(TAG, "testSendMmsMessage skipped: not SMS capable");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.i(TAG, "testSendMmsMessage skipped: no telephony available");
             return;
         }
 
         Log.i(TAG, "testSendMmsMessage");
+        // Prime the MmsService so that MMS config is loaded
+        final SmsManager smsManager = SmsManager.getDefault();
+        smsManager.getAutoPersisting();
+        // MMS config is loaded asynchronously. Wait a bit so it will be loaded.
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            // Ignore
+        }
+
         final Context context = getContext();
         // Register sent receiver
         mSentReceiver = new SentReceiver();
@@ -193,7 +206,7 @@
         // Send
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(
                 context, 0, new Intent(ACTION_MMS_SENT), 0);
-        SmsManager.getDefault().sendMultimediaMessage(context,
+        smsManager.sendMultimediaMessage(context,
                 contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
         assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT));
         sendFile.delete();
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 41fe996..8b94d00 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -225,7 +225,10 @@
                 break;
 
             case TelephonyManager.PHONE_TYPE_NONE:
-                if (mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI) != null) {
+                boolean nwSupported = mCm.isNetworkSupported(mCm.TYPE_WIFI);
+                PackageManager packageManager = getContext().getPackageManager();
+                // only check serial number & MAC address if device report wifi feature
+                if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
                     assertSerialNumber();
                     assertMacAddress(getWifiMacAddress());
                 } else if (mCm.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH) != null) {
diff --git a/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java b/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
index 6eb09eb..9ab815f 100644
--- a/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
+++ b/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
@@ -94,20 +94,20 @@
         final long ONE_SECOND_IN_MS = 1000;
         assertEquals("0 minutes ago",
                 DateUtils.getRelativeTimeSpanString(mBaseTime - ONE_SECOND_IN_MS));
-        assertEquals("in 0 minutes",
+        assertEquals("In 0 minutes",
                 DateUtils.getRelativeTimeSpanString(mBaseTime + ONE_SECOND_IN_MS));
 
         final long ONE_MINUTE_IN_MS = 60 * ONE_SECOND_IN_MS;
         assertEquals("1 minute ago", DateUtils.getRelativeTimeSpanString(0, ONE_MINUTE_IN_MS,
                 DateUtils.MINUTE_IN_MILLIS));
-        assertEquals("in 1 minute", DateUtils.getRelativeTimeSpanString(ONE_MINUTE_IN_MS, 0,
+        assertEquals("In 1 minute", DateUtils.getRelativeTimeSpanString(ONE_MINUTE_IN_MS, 0,
                 DateUtils.MINUTE_IN_MILLIS));
 
         final long ONE_HOUR_IN_MS = 60 * 60 * 1000;
         final long TWO_HOURS_IN_MS = 2 * ONE_HOUR_IN_MS;
         assertEquals("2 hours ago", DateUtils.getRelativeTimeSpanString(mBaseTime - TWO_HOURS_IN_MS,
                 mBaseTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_NUMERIC_DATE));
-        assertEquals("in 2 hours", DateUtils.getRelativeTimeSpanString(mBaseTime + TWO_HOURS_IN_MS,
+        assertEquals("In 2 hours", DateUtils.getRelativeTimeSpanString(mBaseTime + TWO_HOURS_IN_MS,
                 mBaseTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_NUMERIC_DATE));
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index 10d08d0..482edb0 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -255,7 +255,7 @@
 
         assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
                 KeyEvent.KEYCODE_DPAD_UP, noMetaEvent));
-        // |first line
+        // first lin|e
         // second line
         // last line
         assertSelection(0);
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 3c6028f..6514402 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -165,6 +165,9 @@
             // Wait for things to settle.
             getUiDevice().waitForIdle();
 
+            // Wait for Activity draw finish
+            getInstrumentation().waitForIdleSync();
+
             // Clear the window animation stats to be with a clean slate.
             uiAutomation.clearWindowAnimationFrameStats();
 
@@ -177,6 +180,9 @@
             // Wait for things to settle.
             getUiDevice().waitForIdle();
 
+            // Wait for Activity draw finish
+            getInstrumentation().waitForIdleSync();
+
             // Get the frame stats.
             WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
index cb62694..c97e020 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
@@ -28,13 +28,19 @@
  */
 public class SamplePointVerifier extends BitmapVerifier {
     private static final String TAG = "SamplePoint";
-    private Point[] mTestPoints;
-    private int[] mExpectedColors;
-    private int mTolerance = 20;
+    private static final int DEFAULT_TOLERANCE = 20;
+    private final Point[] mTestPoints;
+    private final int[] mExpectedColors;
+    private final int mTolerance;
 
     public SamplePointVerifier(Point[] testPoints, int[] expectedColors) {
+        this(testPoints, expectedColors, DEFAULT_TOLERANCE);
+    }
+
+    public SamplePointVerifier(Point[] testPoints, int[] expectedColors, int tolerance) {
         mTestPoints = testPoints;
         mExpectedColors = expectedColors;
+        mTolerance = tolerance;
     }
 
     @Override
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 2726dac..38777a2 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -16,6 +16,7 @@
 
 package android.uirendering.cts.testclasses;
 
+import android.content.pm.PackageManager;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -163,6 +164,9 @@
 
     @SmallTest
     public void testWebViewClipWithCircle() {
+        if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+            return; // no WebView to run test on
+        }
         createTest()
                 // golden client - draw a simple non-AA circle
                 .addCanvasClient(new CanvasClient() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
index 2061023..4582935 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -32,6 +32,7 @@
         if (getActivity().getOnTv()) {
             shadowColorValue = 0xBB;
         }
+        // Use a higher threshold (30) than default value (20);
         SamplePointVerifier verifier = new SamplePointVerifier(
                 new Point[] {
                         // view area
@@ -46,7 +47,8 @@
                         Color.WHITE,
                         Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
                         Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
-                });
+                },
+                30);
         createTest()
                 .addLayout(R.layout.simple_shadow_layout, null, true/* HW only */)
                 .runWithVerifier(verifier);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index d585f5f..57c67bd 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -48,7 +48,7 @@
                 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
         mHandler = new RenderSpecHandler();
         int uiMode = getResources().getConfiguration().uiMode;
-        mOnTv = (uiMode & Configuration.UI_MODE_TYPE_TELEVISION) == Configuration.UI_MODE_TYPE_TELEVISION;
+        mOnTv = (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
     }
 
     public boolean getOnTv() {
diff --git a/tests/tests/view/src/android/view/cts/MotionEventTest.java b/tests/tests/view/src/android/view/cts/MotionEventTest.java
index cdedca4..10ea33a 100644
--- a/tests/tests/view/src/android/view/cts/MotionEventTest.java
+++ b/tests/tests/view/src/android/view/cts/MotionEventTest.java
@@ -180,6 +180,40 @@
         assertEquals(mMotionEvent2.getDeviceId(), motionEvent.getDeviceId());
     }
 
+    public void testReadFromParcelWithInvalidPointerCountSize() {
+        Parcel parcel = Parcel.obtain();
+        mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+
+        // Move to pointer id count.
+        parcel.setDataPosition(4);
+        parcel.writeInt(17);
+
+        parcel.setDataPosition(0);
+        try {
+            MotionEvent.CREATOR.createFromParcel(parcel);
+            fail("deserialized invalid parcel");
+        } catch (RuntimeException e) {
+            // Expected.
+        }
+    }
+
+    public void testReadFromParcelWithInvalidSampleSize() {
+        Parcel parcel = Parcel.obtain();
+        mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+
+        // Move to sample count.
+        parcel.setDataPosition(2 * 4);
+        parcel.writeInt(0x000f0000);
+
+        parcel.setDataPosition(0);
+        try {
+            MotionEvent.CREATOR.createFromParcel(parcel);
+            fail("deserialized invalid parcel");
+        } catch (RuntimeException e) {
+            // Expected.
+        }
+    }
+
     public void testToString() {
         // make sure this method never throw exception.
         mMotionEvent2.toString();
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index 374c216..fa1ab70 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -19,7 +19,5 @@
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionApp.apk" />
     <option name="run-command:run-command"
          value="settings put secure voice_interaction_service android.voiceinteraction.service/.MainInteractionService" />
-    <option name="run-command:teardown-command"
-         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionTestCases.apk" />
 </configuration>
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
index 0fa89e1..6b47eb4 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
@@ -59,7 +59,16 @@
 
     @Override
     protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mReceiver);
+        if (mReceiver != null) {
+            try {
+                mContext.unregisterReceiver(mReceiver);
+            } catch (IllegalArgumentException e) {
+                // This exception is thrown if mReceiver in
+                // the above call to unregisterReceiver is never registered.
+                // If so, no harm done by ignoring this exception.
+            }
+            mReceiver = null;
+        }
         super.tearDown();
     }
 
diff --git a/tests/tests/voiceinteraction/testapp/AndroidManifest.xml b/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
index 1c9ee71..15069ec 100644
--- a/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
@@ -23,7 +23,7 @@
 
       <activity android:name="TestApp"
                 android:label="Voice Interaction Test App"
-                android:theme="@android:style/Theme.Material.Light">
+                android:theme="@android:style/Theme.DeviceDefault">
           <intent-filter>
               <action android:name="android.intent.action.TEST_APP" />
               <category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index 0a3974d..e3be691 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -17,7 +17,5 @@
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsService.apk" />
     <option name="run-command:run-command"
          value="settings put secure voice_interaction_service android.voicesettings.service/.MainInteractionService" />
-    <option name="run-command:teardown-command"
-         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsTestCases.apk" />
 </configuration>
diff --git a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
index c2b7e18..aff1160 100644
--- a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
+++ b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
@@ -24,6 +24,7 @@
 import static android.provider.Settings.ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE;
 import static android.provider.Settings.EXTRA_BATTERY_SAVER_MODE_ENABLED;
 
+import android.app.VoiceInteractor;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
@@ -138,9 +139,10 @@
 
     @Override
     public void onRequestCompleteVoice(CompleteVoiceRequest request) {
-        CharSequence prompt = request.getVoicePrompt().getVoicePromptAt(0);
+        VoiceInteractor.Prompt prompt = request.getVoicePrompt();
+        CharSequence message = (prompt != null ? prompt.getVoicePromptAt(0) : "(none)");
         Log.i(TAG, "in Session testcasetype = " + mTestType +
-                ", onRequestCompleteVoice recvd. message = " + prompt);
+                ", onRequestCompleteVoice recvd. message = " + message);
         AsyncTaskArg asyncTaskArg = new AsyncTaskArg().setRequest(request).setCompleteReq(true);
         newTask().execute(asyncTaskArg);
     }
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index 8abe396..9ce743e 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -16,6 +16,8 @@
 
 package android.voicesettings.cts;
 
+import static android.provider.Settings.ACTION_VOICE_CONTROL_AIRPLANE_MODE;
+
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.util.Log;
@@ -33,9 +35,20 @@
     }
 
     public void testAll() throws Exception {
+        if (!isIntentSupported(ACTION_VOICE_CONTROL_AIRPLANE_MODE)) {
+            Log.e(TAG, "Voice intent for Airplane Mode NOT supported. existing the test");
+            return;
+        }
+        int mode;
+        try {
+            mode = getMode();
+            Log.i(TAG, "Before testing, AIRPLANE_MODE is set to: " + mode);
+        } catch (Settings.SettingNotFoundException e) {
+            // if the mode is not supported, don't run the test.
+            Log.i(TAG, "airplane mode is not found in Settings. Skipping AirplaneModeTest");
+            return;
+        }
         startTestActivity("AIRPLANE_MODE");
-        int mode = getMode();
-        Log.i(TAG, "Before testing, AIRPLANE_MODE is set to: " + mode);
         if (mode == AIRPLANE_MODE_IS_OFF) {
             // mode is currently OFF.
             // run a test to turn it on.
@@ -70,7 +83,7 @@
         return true;
     }
 
-    private int getMode() throws Exception {
+    private int getMode() throws Settings.SettingNotFoundException {
         return Settings.Global.getInt(mContext.getContentResolver(),
             Settings.Global.AIRPLANE_MODE_ON);
     }
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
index 3d1357a..983e27b 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
@@ -16,6 +16,8 @@
 
 package android.voicesettings.cts;
 
+import static android.provider.Settings.ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE;
+
 import android.content.Context;
 import android.os.PowerManager;
 import android.util.Log;
@@ -30,6 +32,10 @@
     }
 
     public void testAll() throws Exception {
+        if (!isIntentSupported(ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE)) {
+            Log.e(TAG, "Voice intent for Battery Saver Mode NOT supported. existing the test");
+            return;
+        }
         startTestActivity("BATTERYSAVER_MODE");
         boolean modeIsOn = isModeOn();
         Log.i(TAG, "Before testing, BATTERYSAVER_MODE is set to: " + modeIsOn);
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java b/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
index 5386497..529c160 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
@@ -53,10 +54,30 @@
 
     @Override
     protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mActivityDoneReceiver);
+        if (mActivityDoneReceiver != null) {
+            try {
+                mContext.unregisterReceiver(mActivityDoneReceiver);
+            } catch (IllegalArgumentException e) {
+                // This exception is thrown if mActivityDoneReceiver in
+                // the above call to unregisterReceiver is never registered.
+                // If so, no harm done by ignoring this exception.
+            }
+            mActivityDoneReceiver = null;
+        }
         super.tearDown();
     }
 
+    protected boolean isIntentSupported(String intentStr) {
+        Intent intent = new Intent(intentStr);
+        final PackageManager manager = mContext.getPackageManager();
+        assertNotNull(manager);
+        if (manager.resolveActivity(intent, 0) == null) {
+            Log.i(TAG, "No Voice Activity found for the intent: " + intentStr);
+            return false;
+        }
+        return true;
+    }
+
     protected void startTestActivity(String intentSuffix) {
         Intent intent = new Intent();
         intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + intentSuffix);
@@ -69,9 +90,6 @@
     protected void registerBroadcastReceiver(Utils.TestcaseType testCaseType) throws Exception {
         mTestCaseType = testCaseType;
         mLatch = new CountDownLatch(1);
-        if (mActivityDoneReceiver != null) {
-            mContext.unregisterReceiver(mActivityDoneReceiver);
-        }
         mActivityDoneReceiver = new ActivityDoneReceiver();
         mContext.registerReceiver(mActivityDoneReceiver,
                 new IntentFilter(Utils.BROADCAST_INTENT + testCaseType.toString()));
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
index 8c2efbe..420da8f 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
@@ -16,6 +16,7 @@
 
 package android.voicesettings.cts;
 
+import static android.provider.Settings.ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE;
 import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_ENABLED;
 import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_MINUTES;
 
@@ -39,9 +40,20 @@
     }
 
     public void testAll() throws Exception {
+        if (!isIntentSupported(ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE)) {
+            Log.e(TAG, "Voice intent for Zen Mode NOT supported. existing the test");
+            return;
+        }
+        int mode;
+        try {
+            mode = getMode();
+            Log.i(TAG, "Before testing, zen-mode is set to: " + mode);
+        } catch (Settings.SettingNotFoundException e) {
+            // if the mode is not supported, don't run the test.
+            Log.i(TAG, "zen_mode is not found in Settings. Skipping ZenModeTest");
+            return;
+        }
         startTestActivity("ZEN_MODE");
-        int mode = getMode();
-        Log.i(TAG, "Before testing, zen-mode is set to: " + mode);
         if (mode == ZEN_MODE_IS_OFF) {
             // mode is currently OFF.
             // run a test to turn it on.
@@ -85,7 +97,7 @@
         return true;
     }
 
-    private int getMode() throws Exception {
+    private int getMode() throws Settings.SettingNotFoundException {
         return Settings.Global.getInt(mContext.getContentResolver(), ZEN_MODE);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 3130a26..01938c2 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -24,6 +24,7 @@
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
 import android.content.res.Resources.NotFoundException;
 import android.cts.util.PollingCheck;
@@ -4416,9 +4417,18 @@
     public void testSetGetBreakStrategy() {
         TextView tv = new TextView(mActivity);
 
+        final PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
+
         // The default value is from the theme, here the default is BREAK_STRATEGY_HIGH_QUALITY for
-        // TextView.
-        assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
+        // TextView except for Android Wear. The default value for Android Wear is
+        // BREAK_STRATEGY_BALANCED.
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            // Android Wear
+            assertEquals(Layout.BREAK_STRATEGY_BALANCED, tv.getBreakStrategy());
+        } else {
+            // All other form factor.
+            assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
+        }
 
         tv.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
         assertEquals(Layout.BREAK_STRATEGY_SIMPLE, tv.getBreakStrategy());
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index fa930df..782e6ab 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
     @Option(name="cts-install-path", description="the path to the cts installation to use")
     private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
 
-    public static final String CTS_BUILD_VERSION = "6.0_r0";
+    public static final String CTS_BUILD_VERSION = "6.0_r1";
     public static final String CTS_PACKAGE = "com.android.cts.tradefed.testtype";
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
index b5f0dfc..61561a5 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
@@ -17,6 +17,7 @@
 
 import com.android.cts.util.AbiUtils;
 import com.android.cts.tradefed.result.CtsXmlResultReporter;
+import com.android.ddmlib.IDevice;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.build.IFolderBuildInfo;
@@ -49,7 +50,6 @@
     private static final String EXTENDED_INSTRUMENTATION_NAME =
             "com.android.compatibility.common.deviceinfo.DeviceInfoInstrument";
     private static final String DEVICE_INFO_FILES = "device-info-files";
-    private static final String DEVICE_RESULT_DIR = "/sdcard/" + DEVICE_INFO_FILES;
 
     public static final Set<String> IDS = new HashSet<String>();
     public static final Set<String> EXTENDED_IDS = new HashSet<String>();
@@ -87,7 +87,8 @@
             ITestInvocationListener listener, IBuildInfo buildInfo)
             throws DeviceNotAvailableException {
         // Clear files in device test result directory
-        device.executeShellCommand(String.format("rm -rf %s", DEVICE_RESULT_DIR));
+        String deviceResultDir = getDeviceResultDir(device);
+        device.executeShellCommand(String.format("rm -rf %s", deviceResultDir));
         runInstrumentation(device, abi, testApkDir, listener, EXTENDED_APK_NAME,
             EXTENDED_APP_PACKAGE_NAME, EXTENDED_INSTRUMENTATION_NAME);
         // Copy files in remote result directory to local directory
@@ -131,9 +132,12 @@
         localResultDir = new File(localResultDir, DEVICE_INFO_FILES);
         localResultDir.mkdirs();
 
+
+        String deviceResultDir = getDeviceResultDir(device);
+
         // Pull files from device result directory to local result directory
         String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(),
-                DEVICE_RESULT_DIR, localResultDir.getAbsolutePath());
+                deviceResultDir, localResultDir.getAbsolutePath());
         if (!execute(command)) {
             Log.e(LOG_TAG, String.format("Failed to run %s", command));
         }
@@ -148,4 +152,14 @@
             return false;
         }
     }
+
+    private static String getDeviceResultDir(ITestDevice device) {
+        String externalStorePath = device.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
+        if (externalStorePath == null) {
+            Log.e(LOG_TAG, String.format(
+                    "Failed to get external storage path on device %s", device.getSerialNumber()));
+            return null;
+        }
+        return String.format("%s/%s", externalStorePath, DEVICE_INFO_FILES);
+    }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
index f5a3d02..45224f6 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
@@ -254,12 +254,12 @@
             if (perfResult == null) {
                 perfResult = CtsHostStore.removeCtsResult(mDeviceSerial, mAbi, test.toString());
             }
-            if (perfResult != null) {
+            Test result = findTest(test);
+            if (perfResult != null && !result.getResult().equals(CtsTestStatus.FAIL)) {
                 // CTS result is passed in Summary++++Details format.
                 // Extract Summary and Details, and pass them.
                 Matcher m = mCtsLogPattern.matcher(perfResult);
                 if (m.find()) {
-                    Test result = findTest(test);
                     result.setResultStatus(CtsTestStatus.PASS);
                     result.setSummary(m.group(1));
                     result.setDetails(m.group(2));
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
index 43aaf98..6f4d42d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
@@ -63,7 +63,7 @@
     private static final BatchRunConfiguration DEFAULT_CONFIG =
         new BatchRunConfiguration("rgba8888d24s8", "unspecified", "window");
 
-    private static final int UNRESPOSIVE_CMD_TIMEOUT_MS = 60000; // one minute
+    private static final int UNRESPOSIVE_CMD_TIMEOUT_MS = 10*60*1000; // ten minutes
 
     private final String mPackageName;
     private final String mName;
@@ -427,6 +427,7 @@
                 if (!mGotTestResult) {
                     result.allInstancesPassed = false;
                     result.errorMessages.put(mRunConfig, INCOMPLETE_LOG_MESSAGE);
+                    CLog.i("Test %s failed as it ended before receiving result.", mCurrentTestId);
                 }
 
                 if (mLogData && mCurrentTestLog != null && mCurrentTestLog.length() > 0) {
@@ -477,6 +478,7 @@
                 mPendingResults.get(mCurrentTestId)
                         .errorMessages.put(mRunConfig, codeError + ": " + details);
                 mGotTestResult = true;
+                CLog.e("Got invalid result code '%s' for test %s", code, mCurrentTestId);
             }
         }
 
@@ -950,6 +952,7 @@
         private void killDeqpProcess() throws DeviceNotAvailableException,
                 ProcessKillFailureException {
             for (Integer processId : getDeqpProcessPids()) {
+                CLog.i("Killing deqp device process with ID %d", processId);
                 mDevice.executeShellCommand(String.format("kill -9 %d", processId));
             }
 
@@ -958,6 +961,7 @@
             // check that processes actually died
             if (getDeqpProcessPids().iterator().hasNext()) {
                 // a process is still alive, killing failed
+                CLog.w("Failed to kill all deqp processes on device");
                 throw new ProcessKillFailureException();
             }
         }
@@ -1336,15 +1340,19 @@
                     UNRESPOSIVE_CMD_TIMEOUT_MS, TimeUnit.MILLISECONDS);
         } catch (TimeoutException ex) {
             // Opening connection timed out
+            CLog.e("Opening connection timed out for command: '%s'", command);
             throw new AdbComLinkOpenError("opening connection timed out", ex);
         } catch (AdbCommandRejectedException ex) {
             // Command rejected
+            CLog.e("Device rejected command: '%s'", command);
             throw new AdbComLinkOpenError("command rejected", ex);
         } catch (IOException ex) {
             // shell command channel killed
+            CLog.e("Channel died for command: '%s'", command);
             throw new AdbComLinkKilledError("command link killed", ex);
         } catch (ShellCommandUnresponsiveException ex) {
             // shell command halted
+            CLog.e("No output from command in %d ms: '%s'", UNRESPOSIVE_CMD_TIMEOUT_MS, command);
             throw new AdbComLinkKilledError("command link hung", ex);
         }
     }
@@ -1460,11 +1468,14 @@
         // interrupted, try to recover
         if (interruptingError != null) {
             if (interruptingError instanceof AdbComLinkOpenError) {
+                CLog.i("Recovering from comm link error");
                 mDeviceRecovery.recoverConnectionRefused();
             } else if (interruptingError instanceof AdbComLinkKilledError) {
+                CLog.i("Recovering from comm link killed");
                 mDeviceRecovery.recoverComLinkKilled();
             } else if (interruptingError instanceof RunInterruptedException) {
                 // external run interruption request. Terminate immediately.
+                CLog.i("Run termination requested. Throwing forward.");
                 throw (RunInterruptedException)interruptingError;
             } else {
                 CLog.e(interruptingError);
@@ -1473,6 +1484,7 @@
 
             // recoverXXX did not throw => recovery succeeded
         } else if (!parser.wasSuccessful()) {
+            CLog.i("Parse not successful. Will attempt comm link recovery.");
             mDeviceRecovery.recoverComLinkKilled();
             // recoverXXX did not throw => recovery succeeded
         }
@@ -1495,8 +1507,10 @@
                 // This is required so that a consistently crashing or non-existent tests will
                 // not cause futile (non-terminating) re-execution attempts.
                 if (mInstanceListerner.getCurrentTestId() != null) {
+                    CLog.w("Test '%s' started, but not completed", onlyTest);
                     mInstanceListerner.abortTest(onlyTest, INCOMPLETE_LOG_MESSAGE);
                 } else {
+                    CLog.w("Test '%s' could not start", onlyTest);
                     mInstanceListerner.abortTest(onlyTest, NOT_EXECUTABLE_LOG_MESSAGE);
                 }
             } else if (wasTestExecuted) {
@@ -1827,6 +1841,7 @@
                 uninstallTestApk();
             } else {
                 // Pass all tests if OpenGL ES version is not supported
+                CLog.i("Package %s not supported by the device. Tests trivially pass.", mPackageName);
                 fakePassTests(listener);
             }
         } catch (CapabilityQueryFailureException ex) {
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 375b1a0..2eb5145 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -470,6 +470,15 @@
           'android.alarmclock.cts.SetAlarmTest#testAll',
           'android.alarmclock.cts.SnoozeAlarmTest#testAll',
       ],
+      'android.assist' : [
+          'android.assist.cts.AssistantContentViewTest',
+          'android.assist.cts.ExtraAssistDataTest',
+          'android.assist.cts.FocusChangeTest',
+          'android.assist.cts.LargeViewHierarchyTest',
+          'android.assist.cts.ScreenshotTest',
+          'android.assist.cts.TextViewTest',
+          'android.assist.cts.WebViewTest',
+      ],
       'android.calllog' : [
           'android.calllog.cts.CallLogBackupTest#testSingleCallBackup',
       ],
@@ -487,9 +496,16 @@
       'android.voicesettings' : [
           'android.voicesettings.cts.ZenModeTest#testAll',
       ],
+      'com.android.cts.systemui' : [
+          'com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons',
+      ],
       'com.android.cts.app.os' : [
           'com.android.cts.app.os.OsHostTests#testNonExportedActivities',
       ],
+      'com.android.cts.devicepolicy' : [
+          'com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions',
+          'com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions',
+      ],
       '' : []}
 
 def LogGenerateDescription(name):