Merge "Improve CtsApiCoverage error message for missing testApk files" am: 4d6b7740b9 am: 25a7f03ae9 am: 0caad068db
am: 8ead43a8f0

Change-Id: I71eb7c0894d1cada7d2791c27fa5a0aaf4aa7d67
diff --git a/apps/CameraITS/pymodules/its/cv2image.py b/apps/CameraITS/pymodules/its/cv2image.py
index 83e654e..a34d4ce 100644
--- a/apps/CameraITS/pymodules/its/cv2image.py
+++ b/apps/CameraITS/pymodules/its/cv2image.py
@@ -12,27 +12,36 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import matplotlib
-matplotlib.use('Agg')
-
-import its.error
-from matplotlib import pylab
-import sys
-from PIL import Image
-import numpy
-import math
-import unittest
-import cStringIO
-import scipy.stats
-import copy
-import cv2
 import os
+import unittest
+
+import cv2
+import its.device
+import its.error
+import numpy
+
+VGA_HEIGHT = 480
+VGA_WIDTH = 640
+
 
 def scale_img(img, scale=1.0):
     """Scale and image based on a real number scale factor."""
     dim = (int(img.shape[1]*scale), int(img.shape[0]*scale))
     return cv2.resize(img.copy(), dim, interpolation=cv2.INTER_AREA)
 
+
+def gray_scale_img(img):
+    """Return gray scale version of image."""
+    if len(img.shape) == 2:
+        img_gray = img.copy()
+    elif len(img.shape) == 3:
+        if img.shape[2] == 1:
+            img_gray = img[:, :, 0].copy()
+        else:
+            img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
+    return img_gray
+
+
 class Chart(object):
     """Definition for chart object.
 
@@ -57,6 +66,9 @@
         self._scale_start = scale_start
         self._scale_stop = scale_stop
         self._scale_step = scale_step
+        self.xnorm, self.ynorm, self.wnorm, self.hnorm, self.scale = its.image.chart_located_per_argv()
+        if not self.xnorm:
+            self.locate()
 
     def _calc_scale_factors(self, cam, props, fmt, s, e, fd):
         """Take an image with s, e, & fd to find the chart location.
@@ -79,7 +91,7 @@
         req['android.lens.focusDistance'] = fd
         cap_chart = its.image.stationary_lens_cap(cam, req, fmt)
         img_3a = its.image.convert_capture_to_rgb_image(cap_chart, props)
-        img_3a = its.image.flip_mirror_img_per_argv(img_3a)
+        img_3a = its.image.rotate_img_per_argv(img_3a)
         its.image.write_image(img_3a, 'af_scene.jpg')
         template = cv2.imread(self._file, cv2.IMREAD_ANYDEPTH)
         focal_l = cap_chart['metadata']['android.lens.focalLength']
@@ -95,8 +107,15 @@
         print 'Chart/image scale factor = %.2f' % scale_factor
         return template, img_3a, scale_factor
 
-    def locate(self, cam, props, fmt, s, e, fd):
-        """Find the chart in the image.
+    def locate(self, cam=None, props=None, fmt=None, s=0, e=0, fd=0):
+        """Find the chart in the image, and append location to chart object.
+
+        The values appended are:
+            xnorm:          float; [0, 1] left loc of chart in scene
+            ynorm:          float; [0, 1] top loc of chart in scene
+            wnorm:          float; [0, 1] width of chart in scene
+            hnorm:          float; [0, 1] height of chart in scene
+            scale:          float; scale factor to extract chart
 
         Args:
             cam:            An open device session
@@ -107,29 +126,30 @@
             e:              Exposure time for the AF request as defined in
                             android.sensor.exposureTime
             fd:             float; autofocus lens position
-
-        Returns:
-            xnorm:          float; [0, 1] left loc of chart in scene
-            ynorm:          float; [0, 1] top loc of chart in scene
-            wnorm:          float; [0, 1] width of chart in scene
-            hnorm:          float; [0, 1] height of chart in scene
         """
-        chart, scene, s_factor = self._calc_scale_factors(cam, props, fmt,
-                                                          s, e, fd)
+        if cam:
+            chart, scene, s_factor = self._calc_scale_factors(cam, props, fmt,
+                                                              s, e, fd)
+        else:
+            with its.device.ItsSession() as cam:
+                props = cam.get_camera_properties()
+                fmt = {'format': 'yuv', 'width': VGA_WIDTH,
+                       'height': VGA_HEIGHT}
+
+                # Get sensitivity, exposure time, and focus distance with 3A.
+                s, e, _, _, fd = cam.do_3a(get_results=True)
+
+                chart, scene, s_factor = self._calc_scale_factors(cam, props,
+                                                                  fmt, s, e, fd)
         scale_start = self._scale_start * s_factor
         scale_stop = self._scale_stop * s_factor
         scale_step = self._scale_step * s_factor
+        self.scale = s_factor
         max_match = []
         # check for normalized image
         if numpy.amax(scene) <= 1.0:
             scene = (scene * 255.0).astype(numpy.uint8)
-        if len(scene.shape) == 2:
-            scene_gray = scene.copy()
-        elif len(scene.shape) == 3:
-            if scene.shape[2] == 1:
-                scene_gray = scene[:, :, 0]
-            else:
-                scene_gray = cv2.cvtColor(scene.copy(), cv2.COLOR_RGB2GRAY)
+        scene_gray = gray_scale_img(scene)
         print 'Finding chart in scene...'
         for scale in numpy.arange(scale_start, scale_stop, scale_step):
             scene_scaled = scale_img(scene_gray, scale)
@@ -142,26 +162,36 @@
         # determine if optimization results are valid
         opt_values = [x[0] for x in max_match]
         if 2.0*min(opt_values) > max(opt_values):
-            estring = ('Unable to find chart in scene!\n'
+            estring = ('Warning: unable to find chart in scene!\n'
                        'Check camera distance and self-reported '
                        'pixel pitch, focal length and hyperfocal distance.')
-            raise its.error.Error(estring)
-        # find max and draw bbox
-        match_index = max_match.index(max(max_match, key=lambda x: x[0]))
-        scale = scale_start + scale_step * match_index
-        print 'Optimum scale factor: %.3f' %  scale
-        top_left_scaled = max_match[match_index][1]
-        h, w = chart.shape
-        bottom_right_scaled = (top_left_scaled[0] + w, top_left_scaled[1] + h)
-        top_left = (int(top_left_scaled[0]/scale),
-                    int(top_left_scaled[1]/scale))
-        bottom_right = (int(bottom_right_scaled[0]/scale),
-                        int(bottom_right_scaled[1]/scale))
-        wnorm = float((bottom_right[0]) - top_left[0]) / scene.shape[1]
-        hnorm = float((bottom_right[1]) - top_left[1]) / scene.shape[0]
-        xnorm = float(top_left[0]) / scene.shape[1]
-        ynorm = float(top_left[1]) / scene.shape[0]
-        return xnorm, ynorm, wnorm, hnorm
+            print estring
+            self.wnorm = 1.0
+            self.hnorm = 1.0
+            self.xnorm = 0.0
+            self.ynorm = 0.0
+        else:
+            if (max(opt_values) == opt_values[0] or
+                        max(opt_values) == opt_values[len(opt_values)-1]):
+                estring = ('Warning: chart is at extreme range of locator '
+                           'check.\n')
+                print estring
+            # find max and draw bbox
+            match_index = max_match.index(max(max_match, key=lambda x: x[0]))
+            self.scale = scale_start + scale_step * match_index
+            print 'Optimum scale factor: %.3f' %  self.scale
+            top_left_scaled = max_match[match_index][1]
+            h, w = chart.shape
+            bottom_right_scaled = (top_left_scaled[0] + w,
+                                   top_left_scaled[1] + h)
+            top_left = (int(top_left_scaled[0]/self.scale),
+                        int(top_left_scaled[1]/self.scale))
+            bottom_right = (int(bottom_right_scaled[0]/self.scale),
+                            int(bottom_right_scaled[1]/self.scale))
+            self.wnorm = float((bottom_right[0]) - top_left[0]) / scene.shape[1]
+            self.hnorm = float((bottom_right[1]) - top_left[1]) / scene.shape[0]
+            self.xnorm = float(top_left[0]) / scene.shape[1]
+            self.ynorm = float(top_left[1]) / scene.shape[0]
 
 
 class __UnitTest(unittest.TestCase):
@@ -186,7 +216,8 @@
             blur = cv2.blur(chart, (j, j))
             blur = blur[:, :, numpy.newaxis]
             sharpness[j] = (yuv_full_scale *
-                    its.image.compute_image_sharpness(blur / white_level))
+                            its.image.compute_image_sharpness(blur /
+                                                              white_level))
         self.assertTrue(numpy.isclose(sharpness[2]/sharpness[4],
                                       numpy.sqrt(2), atol=0.1))
         self.assertTrue(numpy.isclose(sharpness[4]/sharpness[8],
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index d47a995..d4f51f6 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -626,7 +626,10 @@
     ytile = math.ceil(ynorm * hfull)
     wtile = math.floor(wnorm * wfull)
     htile = math.floor(hnorm * hfull)
-    return img[ytile:ytile+htile,xtile:xtile+wtile,:].copy()
+    if len(img.shape)==2:
+        return img[ytile:ytile+htile,xtile:xtile+wtile].copy()
+    else:
+        return img[ytile:ytile+htile,xtile:xtile+wtile,:].copy()
 
 def compute_image_means(img):
     """Calculate the mean of each color channel in the image.
@@ -755,6 +758,7 @@
     [gy, gx] = numpy.gradient(luma)
     return numpy.average(numpy.sqrt(gy*gy + gx*gx))
 
+
 def normalize_img(img):
     """Normalize the image values to between 0 and 1.
 
@@ -765,21 +769,39 @@
     """
     return (img - numpy.amin(img))/(numpy.amax(img) - numpy.amin(img))
 
-def flip_mirror_img_per_argv(img):
-    """Flip/mirror an image if "flip" or "mirror" is in argv
+
+def chart_located_per_argv():
+    """Determine if chart already located outside of test.
+
+    If chart info provided, return location and size. If not, return None.
+
+    Args:
+        None
+    Returns:
+        chart_loc:  float converted xnorm,ynorm,wnorm,hnorm,scale from argv text.
+                    argv is of form 'chart_loc=0.45,0.45,0.1,0.1,1.0'
+    """
+    for s in sys.argv[1:]:
+        if s[:10] == "chart_loc=" and len(s) > 10:
+            chart_loc = s[10:].split(",")
+            return map(float, chart_loc)
+    return None, None, None, None, None
+
+
+def rotate_img_per_argv(img):
+    """Rotate an image 180 degrees if "rotate" is in argv
 
     Args:
         img: 2-D numpy array of image values
     Returns:
-        Flip/mirrored image
+        Rotated image
     """
     img_out = img
-    if "flip" in sys.argv:
-        img_out = numpy.flipud(img_out)
-    if "mirror" in sys.argv:
-        img_out = numpy.fliplr(img_out)
+    if "rotate180" in sys.argv:
+        img_out = numpy.fliplr(numpy.flipud(img_out))
     return img_out
 
+
 def stationary_lens_cap(cam, req, fmt):
     """Take up to NUM_TRYS caps and save the 1st one with lens stationary.
 
@@ -804,6 +826,7 @@
             raise its.error.Error('Cannot settle lens after %d trys!' % trys)
     return cap[NUM_FRAMES-1]
 
+
 class __UnitTest(unittest.TestCase):
     """Run a suite of unit tests on this module.
     """
diff --git a/apps/CameraITS/tests/scene2/test_faces.py b/apps/CameraITS/tests/scene2/test_faces.py
index 4e30fc1..2acce85 100644
--- a/apps/CameraITS/tests/scene2/test_faces.py
+++ b/apps/CameraITS/tests/scene2/test_faces.py
@@ -60,7 +60,7 @@
                 # but it should detect at least one face in last frame
                 if i == NUM_TEST_FRAMES - 1:
                     img = its.image.convert_capture_to_rgb_image(cap, props=props)
-                    img = its.image.flip_mirror_img_per_argv(img)
+                    img = its.image.rotate_img_per_argv(img)
                     img_name = "%s_fd_mode_%s.jpg" % (NAME, fd_mode)
                     its.image.write_image(img, img_name)
                     if len(faces) == 0:
diff --git a/apps/CameraITS/tests/scene3/test_flip_mirror.py b/apps/CameraITS/tests/scene3/test_flip_mirror.py
new file mode 100644
index 0000000..86d96f1
--- /dev/null
+++ b/apps/CameraITS/tests/scene3/test_flip_mirror.py
@@ -0,0 +1,130 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import cv2
+
+import its.caps
+import its.cv2image
+import its.device
+import its.image
+import its.objects
+import numpy as np
+
+NAME = os.path.basename(__file__).split('.')[0]
+CHART_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
+                          'test_images', 'ISO12233.png')
+CHART_HEIGHT = 13.5  # cm
+CHART_DISTANCE = 30.0  # cm
+CHART_SCALE_START = 0.65
+CHART_SCALE_STOP = 1.35
+CHART_SCALE_STEP = 0.025
+CHART_ORIENTATIONS = ['nominal', 'flip', 'mirror', 'rotate']
+VGA_WIDTH = 640
+VGA_HEIGHT = 480
+(X_CROP, Y_CROP) = (0.5, 0.5)  # crop center area of ISO12233 chart
+
+
+def test_flip_mirror(cam, props, fmt, chart):
+    """Return if image is flipped or mirrored.
+
+    Args:
+        cam (class): An open device session
+        props (class): Properties of cam
+        fmt (dict): Capture format
+        chart (class): Object with chart properties
+
+    Returns:
+        boolean: True if flipped, False if not
+    """
+
+    # determine if in debug mode
+    debug = its.caps.debug_mode()
+
+    # get a local copy of the chart template
+    template = cv2.imread(CHART_FILE, cv2.IMREAD_ANYDEPTH)
+
+    # take img, crop chart, scale and prep for cv2 template match
+    req = its.objects.auto_capture_request()
+    cap = cam.do_capture(req, fmt)
+    y, _, _ = its.image.convert_capture_to_planes(cap, props)
+    y = its.image.rotate_img_per_argv(y)
+    patch = its.image.get_image_patch(y, chart.xnorm, chart.ynorm,
+                                      chart.wnorm, chart.hnorm)
+    patch = 255 * its.cv2image.gray_scale_img(patch)
+    patch = its.cv2image.scale_img(patch.astype(np.uint8), chart.scale)
+
+    # save full images if in debug
+    if debug:
+        its.image.write_image(template[:, :, np.newaxis]/255.0,
+                              '%s_template.jpg' % NAME)
+
+    # save patch
+    its.image.write_image(patch[:, :, np.newaxis]/255.0,
+                          '%s_scene_patch.jpg' % NAME)
+
+    # crop center areas and strip off any extra rows/columns
+    template = its.image.get_image_patch(template, (1-X_CROP)/2, (1-Y_CROP)/2,
+                                         X_CROP, Y_CROP)
+    patch = its.image.get_image_patch(patch, (1-X_CROP)/2,
+                                      (1-Y_CROP)/2, X_CROP, Y_CROP)
+    patch = patch[0:min(patch.shape[0], template.shape[0]),
+                  0:min(patch.shape[1], template.shape[1])]
+    comp_chart = patch
+
+    # determine optimum orientation
+    opts = []
+    for orientation in CHART_ORIENTATIONS:
+        if orientation == 'flip':
+            comp_chart = np.flipud(patch)
+        elif orientation == 'mirror':
+            comp_chart = np.fliplr(patch)
+        elif orientation == 'rotate':
+            comp_chart = np.flipud(np.fliplr(patch))
+        correlation = cv2.matchTemplate(comp_chart, template, cv2.TM_CCOEFF)
+        _, opt_val, _, _ = cv2.minMaxLoc(correlation)
+        if debug:
+            cv2.imwrite('%s_%s.jpg' % (NAME, orientation), comp_chart)
+        print ' %s correlation value: %d' % (orientation, opt_val)
+        opts.append(opt_val)
+
+    # determine if 'nominal' or 'rotated' is best orientation
+    assert_flag = (opts[0] == max(opts) or opts[3] == max(opts))
+    assert assert_flag, ('Optimum orientation is %s' %
+                         CHART_ORIENTATIONS[np.argmax(opts)])
+    # print warning if rotated
+    if opts[3] == max(opts):
+        print 'Image is rotated 180 degrees. Try "rotate" flag.'
+
+
+def main():
+    """Test if image is properly oriented."""
+
+    print '\nStarting test_flip_mirror.py'
+
+    # initialize chart class and locate chart in scene
+    chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+                               CHART_SCALE_START, CHART_SCALE_STOP,
+                               CHART_SCALE_STEP)
+
+    with its.device.ItsSession() as cam:
+        props = cam.get_camera_properties()
+        fmt = {'format': 'yuv', 'width': VGA_WIDTH, 'height': VGA_HEIGHT}
+
+        # test that image is not flipped, mirrored, or rotated
+        test_flip_mirror(cam, props, fmt, chart)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
index cd563be..24c6841 100644
--- a/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
+++ b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
@@ -37,19 +37,20 @@
 CHART_SCALE_STEP = 0.025
 
 
-def test_lens_movement_reporting(cam, props, fmt, sensitivity, exp, af_fd):
+def test_lens_movement_reporting(cam, props, fmt, gain, exp, af_fd, chart):
     """Return fd, sharpness, lens state of the output images.
 
     Args:
         cam: An open device session.
         props: Properties of cam
         fmt: dict; capture format
-        sensitivity: Sensitivity for the 3A request as defined in
+        gain: Sensitivity for the 3A request as defined in
             android.sensor.sensitivity
         exp: Exposure time for the 3A request as defined in
             android.sensor.exposureTime
         af_fd: Focus distance for the 3A request as defined in
             android.lens.focusDistance
+        chart: Object that contains chart information
 
     Returns:
         Object containing reported sharpness of the output image, keyed by
@@ -57,15 +58,6 @@
             'sharpness'
     """
 
-    # initialize chart class
-    chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
-                               CHART_SCALE_START, CHART_SCALE_STOP,
-                               CHART_SCALE_STEP)
-
-    # find chart location
-    xnorm, ynorm, wnorm, hnorm = chart.locate(cam, props, fmt, sensitivity,
-                                              exp, af_fd)
-
     # initialize variables and take data sets
     data_set = {}
     white_level = int(props['android.sensor.info.whiteLevel'])
@@ -74,7 +66,7 @@
     fds = sorted(fds * NUM_IMGS)
     reqs = []
     for i, fd in enumerate(fds):
-        reqs.append(its.objects.manual_capture_request(sensitivity, exp))
+        reqs.append(its.objects.manual_capture_request(gain, exp))
         reqs[i]['android.lens.focusDistance'] = fd
     caps = cam.do_capture(reqs, fmt)
     for i, cap in enumerate(caps):
@@ -92,12 +84,12 @@
         print ' current lens location (diopters): %.3f' % data['loc']
         print ' lens moving %r' % data['lens_moving']
         y, _, _ = its.image.convert_capture_to_planes(cap, props)
-        y = its.image.flip_mirror_img_per_argv(y)
-        chart = its.image.normalize_img(its.image.get_image_patch(y,
-                                                                  xnorm, ynorm,
-                                                                  wnorm, hnorm))
-        its.image.write_image(chart, '%s_i=%d_chart.jpg' % (NAME, i))
-        data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+        y = its.image.rotate_img_per_argv(y)
+        chart.img = its.image.normalize_img(its.image.get_image_patch(
+                y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+        its.image.write_image(chart.img, '%s_i=%d_chart.jpg' % (NAME, i))
+        data['sharpness'] = white_level*its.image.compute_image_sharpness(
+                chart.img)
         print 'Chart sharpness: %.1f\n' % data['sharpness']
         data_set[i] = data
     return data_set
@@ -110,6 +102,11 @@
     """
 
     print '\nStarting test_lens_movement_reporting.py'
+    # initialize chart class
+    chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+                               CHART_SCALE_START, CHART_SCALE_STOP,
+                               CHART_SCALE_STEP)
+
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
         its.caps.skip_unless(not its.caps.fixed_focus(props))
@@ -121,7 +118,7 @@
         s, e, _, _, fd = cam.do_3a(get_results=True)
 
         # Get sharpness for each focal distance
-        d = test_lens_movement_reporting(cam, props, fmt, s, e, fd)
+        d = test_lens_movement_reporting(cam, props, fmt, s, e, fd, chart)
         for k in sorted(d):
             print ('i: %d\tfd: %.3f\tlens location (diopters): %.3f \t'
                    'sharpness: %.1f  \tlens_moving: %r \t'
diff --git a/apps/CameraITS/tests/scene3/test_lens_position.py b/apps/CameraITS/tests/scene3/test_lens_position.py
index f850e3d..2194b8c 100644
--- a/apps/CameraITS/tests/scene3/test_lens_position.py
+++ b/apps/CameraITS/tests/scene3/test_lens_position.py
@@ -38,7 +38,7 @@
 CHART_SCALE_STEP = 0.025
 
 
-def test_lens_position(cam, props, fmt, sensitivity, exp, af_fd):
+def test_lens_position(cam, props, fmt, sensitivity, exp, chart):
     """Return fd, sharpness, lens state of the output images.
 
     Args:
@@ -49,8 +49,7 @@
             android.sensor.sensitivity
         exp: Exposure time for the 3A request as defined in
             android.sensor.exposureTime
-        af_fd: Focus distance for the 3A request as defined in
-            android.lens.focusDistance
+        chart: Object with chart properties
 
     Returns:
         Dictionary of results for different focal distance captures
@@ -58,15 +57,6 @@
         d_static, d_moving
     """
 
-    # initialize chart class
-    chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
-                                CHART_SCALE_START, CHART_SCALE_STOP,
-                                CHART_SCALE_STEP)
-
-    # find chart location
-    xnorm, ynorm, wnorm, hnorm = chart.locate(cam, props, fmt, sensitivity,
-                                              exp, af_fd)
-
     # initialize variables and take data sets
     data_static = {}
     data_moving = {}
@@ -89,11 +79,11 @@
         print ' focus distance (diopters): %.3f' % data['fd']
         print ' current lens location (diopters): %.3f' % data['loc']
         y, _, _ = its.image.convert_capture_to_planes(cap, props)
-        chart = its.image.normalize_img(its.image.get_image_patch(y,
-                                                                  xnorm, ynorm,
-                                                                  wnorm, hnorm))
-        its.image.write_image(chart, '%s_stat_i=%d_chart.jpg' % (NAME, i))
-        data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+        chart.img = its.image.normalize_img(its.image.get_image_patch(
+                y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+        its.image.write_image(chart.img, '%s_stat_i=%d_chart.jpg' % (NAME, i))
+        data['sharpness'] = white_level*its.image.compute_image_sharpness(
+                chart.img)
         print 'Chart sharpness: %.1f\n' % data['sharpness']
         data_static[i] = data
     # take moving data set
@@ -115,12 +105,12 @@
         print ' focus distance (diopters): %.3f' % data['fd']
         print ' current lens location (diopters): %.3f' % data['loc']
         y, _, _ = its.image.convert_capture_to_planes(cap, props)
-        y = its.image.flip_mirror_img_per_argv(y)
-        chart = its.image.normalize_img(its.image.get_image_patch(y,
-                                                                  xnorm, ynorm,
-                                                                  wnorm, hnorm))
-        its.image.write_image(chart, '%s_move_i=%d_chart.jpg' % (NAME, i))
-        data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+        y = its.image.rotate_img_per_argv(y)
+        chart.img = its.image.normalize_img(its.image.get_image_patch(
+                y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+        its.image.write_image(chart.img, '%s_move_i=%d_chart.jpg' % (NAME, i))
+        data['sharpness'] = white_level*its.image.compute_image_sharpness(
+                chart.img)
         print 'Chart sharpness: %.1f\n' % data['sharpness']
         data_moving[i] = data
     return data_static, data_moving
@@ -128,19 +118,23 @@
 
 def main():
     """Test if focus position is properly reported for moving lenses."""
-
     print '\nStarting test_lens_position.py'
+    # initialize chart class
+    chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+                               CHART_SCALE_START, CHART_SCALE_STOP,
+                               CHART_SCALE_STEP)
+
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
         its.caps.skip_unless(not its.caps.fixed_focus(props))
         its.caps.skip_unless(its.caps.lens_calibrated(props))
         fmt = {'format': 'yuv', 'width': VGA_WIDTH, 'height': VGA_HEIGHT}
 
-        # Get proper sensitivity, exposure time, and focus distance with 3A.
-        s, e, _, _, fd = cam.do_3a(get_results=True)
+        # Get proper sensitivity and exposure time with 3A
+        s, e, _, _, _ = cam.do_3a(get_results=True)
 
         # Get sharpness for each focal distance
-        d_stat, d_move = test_lens_position(cam, props, fmt, s, e, fd)
+        d_stat, d_move = test_lens_position(cam, props, fmt, s, e, chart)
         print 'Lens stationary'
         for k in sorted(d_stat):
             print ('i: %d\tfd: %.3f\tlens location (diopters): %.3f \t'
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index e8a5b81..faacaf9 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -116,7 +116,7 @@
             # Split by comma and convert each dimension to int.
             [w, h] = map(int, s[9:].split(","))
         elif s[:12] == "test_length=" and len(s) > 12:
-            test_length = int(s[12:])
+            test_length = float(s[12:])
 
     # Collect or load the camera+gyro data. All gyro events as well as camera
     # timestamps are in the "events" dictionary, and "frames" is a list of
@@ -345,7 +345,7 @@
         if num_features < MIN_FEATURE_PTS:
             print "Not enough feature points in frame", i
             print "Need at least %d features, got %d" % (
-                    MIN_FEATURE_PTS, num_features)
+                MIN_FEATURE_PTS, num_features)
             assert 0
         else:
             print "Number of features in frame %d is %d" % (i, num_features)
@@ -447,13 +447,12 @@
         fmt = {"format": "yuv", "width": w, "height": h}
         s, e, _, _, _ = cam.do_3a(get_results=True, do_af=False)
         req = its.objects.manual_capture_request(s, e)
-        fps = 30
         req["android.lens.focusDistance"] = 1 / (CHART_DISTANCE * CM_TO_M)
         req["android.control.aeTargetFpsRange"] = [fps, fps]
         req["android.sensor.frameDuration"] = int(1000.0/fps * MSEC_TO_NSEC)
-        print "Capturing %dx%d with sens. %d, exp. time %.1fms" % (
-            w, h, s, e*NSEC_TO_MSEC)
-        caps = cam.do_capture([req]*fps*test_length, fmt)
+        print "Capturing %dx%d with sens. %d, exp. time %.1fms at %dfps" % (
+            w, h, s, e*NSEC_TO_MSEC, fps)
+        caps = cam.do_capture([req]*int(fps*test_length), fmt)
 
         # Get the gyro events.
         print "Reading out sensor events"
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index a6fc759..15dd837 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -21,13 +21,24 @@
 import sys
 
 import its.caps
+import its.cv2image
 import its.device
+import its.image
 from its.device import ItsSession
 
 CHART_DELAY = 1  # seconds
+CHART_DISTANCE = 30.0  # cm
+CHART_HEIGHT = 13.5  # cm
+CHART_SCALE_START = 0.65
+CHART_SCALE_STOP = 1.35
+CHART_SCALE_STEP = 0.025
 FACING_EXTERNAL = 2
 NUM_TRYS = 2
+SCENE3_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
+                           'test_images', 'ISO12233.png')
 SKIP_RET_CODE = 101  # note this must be same as tests/scene*/test_*
+VGA_HEIGHT = 480
+VGA_WIDTH = 640
 
 
 def evaluate_socket_failure(err_file_path):
@@ -98,6 +109,7 @@
             ],
         "scene3": [
             "test_3a_consistency",
+            "test_flip_mirror",
             "test_lens_movement_reporting",
             "test_lens_position"
             ],
@@ -294,6 +306,15 @@
                     valid_scene_code = subprocess.call(cmd, cwd=topdir)
                     assert valid_scene_code == 0
             print "Start running ITS on camera %s, %s" % (camera_id, scene)
+            # Extract chart from scene for scene3 once up front
+            chart_loc_arg = ''
+            if scene == 'scene3':
+                chart = its.cv2image.Chart(SCENE3_FILE, CHART_HEIGHT,
+                                           CHART_DISTANCE, CHART_SCALE_START,
+                                           CHART_SCALE_STOP, CHART_SCALE_STEP)
+                chart_loc_arg = 'chart_loc=%.2f,%.2f,%.2f,%.2f,%.3f' % (
+                        chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm,
+                        chart.scale)
             # Run each test, capturing stdout and stderr.
             for (testname, testpath) in tests:
                 if auto_scene_switch:
@@ -325,7 +346,7 @@
                             test_code = skip_code
                     if skip_code is not SKIP_RET_CODE:
                         cmd = ['python', os.path.join(os.getcwd(), testpath)]
-                        cmd += sys.argv[1:] + [camera_id_arg]
+                        cmd += sys.argv[1:] + [camera_id_arg] + [chart_loc_arg]
                         with open(outpath, 'w') as fout, open(errpath, 'w') as ferr:
                             test_code = subprocess.call(
                                 cmd, stderr=ferr, stdout=fout, cwd=outdir)
diff --git a/apps/CameraITS/tools/run_sensor_fusion_box.py b/apps/CameraITS/tools/run_sensor_fusion_box.py
index ec16b3d..650a1f6 100644
--- a/apps/CameraITS/tools/run_sensor_fusion_box.py
+++ b/apps/CameraITS/tools/run_sensor_fusion_box.py
@@ -104,6 +104,7 @@
 
     fps_arg = 'fps=' + fps
     test_length_arg = 'test_length=' + test_length
+    print 'Capturing at %sfps' % fps
 
     os.mkdir(os.path.join(tmpdir, camera_id))
 
diff --git a/apps/CtsVerifier/res/values-watch/strings.xml b/apps/CtsVerifier/res/values-watch/strings.xml
index 6f1470c..37ad24f 100644
--- a/apps/CtsVerifier/res/values-watch/strings.xml
+++ b/apps/CtsVerifier/res/values-watch/strings.xml
@@ -24,4 +24,14 @@
       perform a palm press to turn off display and put device into suspend mode. The screen will
       turn on and device will vibrate once all the tests are completed.
     </string>
+
+    <string name="da_tapjacking_instructions">
+        1. Launch the device admin add screen by pressing the button below.\n
+        2. Wait for an overlaying transparent activity to show up obscuring the device admin details window.\n
+        3. The button to activate the admin should be disabled and should not register any taps.\n
+        4. Wait 10 seconds for the overlaying transparent activity to go away.\n
+        5. Exit the device admin details and return to this screen.\n
+        Pass the test if the device admin could not be activated while the details
+        window was being obscured.
+    </string>
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
index 52c7ed5..e81f301 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 
 import android.app.Activity;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.view.WindowManager;
 
@@ -30,6 +31,8 @@
 
 public class OverlayingActivity extends Activity {
 
+    private static final long ACTIVITY_TIMEOUT_ON_WATCH = 10_000;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -37,5 +40,9 @@
         WindowManager.LayoutParams params = getWindow().getAttributes();
         params.flags = FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE
                 | FLAG_KEEP_SCREEN_ON;
+        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            getWindow().getDecorView().postDelayed(() -> OverlayingActivity.this.finish(),
+                    ACTIVITY_TIMEOUT_ON_WATCH);
+        }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
index a4adfda..a960c67 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -261,19 +261,18 @@
                         new ButtonInfo(R.string.enterprise_privacy_finish,
                                 buildCommandIntent(
                                         CommandReceiverActivity.COMMAND_REMOVE_MANAGED_PROFILE))}));
-        // Disabled for API 26 due to b/63696536.
-        // adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_FAILED_PASSWORD_WIPE,
-        //         R.string.enterprise_privacy_failed_password_wipe,
-        //         R.string.enterprise_privacy_failed_password_wipe_info,
-        //         new ButtonInfo[] {
-        //                 new ButtonInfo(R.string.enterprise_privacy_open_settings,
-        //                         new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
-        //                 new ButtonInfo(R.string.enterprise_privacy_set_limit,
-        //                         buildCommandIntent(CommandReceiverActivity
-        //                                 .COMMAND_SET_MAXIMUM_PASSWORD_ATTEMPTS)),
-        //                 new ButtonInfo(R.string.enterprise_privacy_finish,
-        //                         buildCommandIntent(CommandReceiverActivity
-        //                                 .COMMAND_CLEAR_MAXIMUM_PASSWORD_ATTEMPTS))}));
+        adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_FAILED_PASSWORD_WIPE,
+                R.string.enterprise_privacy_failed_password_wipe,
+                R.string.enterprise_privacy_failed_password_wipe_info,
+                new ButtonInfo[] {
+                        new ButtonInfo(R.string.enterprise_privacy_open_settings,
+                                new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
+                        new ButtonInfo(R.string.enterprise_privacy_set_limit,
+                                buildCommandIntent(CommandReceiverActivity
+                                        .COMMAND_SET_MAXIMUM_PASSWORD_ATTEMPTS)),
+                        new ButtonInfo(R.string.enterprise_privacy_finish,
+                                buildCommandIntent(CommandReceiverActivity
+                                        .COMMAND_CLEAR_MAXIMUM_PASSWORD_ATTEMPTS))}));
         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {
             adapter.add(createInteractiveTestItem(this,
                     ENTERPRISE_PRIVACY_COMP_FAILED_PASSWORD_WIPE,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
index 7cfa040..b8cb0e8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
@@ -356,7 +356,7 @@
                     Log.e(TAG, "failed to unpack data from mocklistener", e);
                 }
             }
-            pass &= found.size() == 3;
+            pass &= found.size() >= 3;
             status = pass ? PASS : FAIL;
         }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 9f8438e..9aaf519 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -265,9 +265,6 @@
                                 "data integrity test: notification ID (%d, %d)");
                         pass &= checkEquals(mWhen3, payload.getLong(JSON_WHEN),
                                 "data integrity test: notification when (%d, %d)");
-                    } else {
-                        pass = false;
-                        logFail("unexpected notification tag: " + tag);
                     }
                 } catch (JSONException e) {
                     pass = false;
@@ -275,7 +272,7 @@
                 }
             }
 
-            pass &= found.size() == 3;
+            pass &= found.size() >= 3;
             status = pass ? PASS : FAIL;
         }
 
diff --git a/apps/PermissionApp/AndroidManifest.xml b/apps/PermissionApp/AndroidManifest.xml
index 82e3617..f880933 100644
--- a/apps/PermissionApp/AndroidManifest.xml
+++ b/apps/PermissionApp/AndroidManifest.xml
@@ -21,6 +21,7 @@
     <uses-sdk android:minSdkVersion="23"/>
 
     <uses-permission android:name="android.permission.READ_CONTACTS"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
 
     <application android:label="CtsPermissionApp"
             android:icon="@drawable/ic_permissionapp">
diff --git a/common/device-side/nativetesthelper/Android.mk b/common/device-side/nativetesthelper/Android.mk
new file mode 100644
index 0000000..19f584d
--- /dev/null
+++ b/common/device-side/nativetesthelper/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-devicesidelib
+LOCAL_MODULE := nativetesthelper
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/device-side/nativetesthelper/jni/Android.mk b/common/device-side/nativetesthelper/jni/Android.mk
new file mode 100644
index 0000000..f970e8c
--- /dev/null
+++ b/common/device-side/nativetesthelper/jni/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This is the shared library included by the JNI test app.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libnativetesthelper_jni
+
+LOCAL_SRC_FILES := \
+        gtest_wrapper.cpp
+
+LOCAL_SHARED_LIBRARIES := libnativehelper_compat_libc++
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_ndk_c++
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libgtest_ndk_c++
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_MULTILIB := both
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/common/device-side/nativetesthelper/jni/gtest_wrapper.cpp b/common/device-side/nativetesthelper/jni/gtest_wrapper.cpp
new file mode 100644
index 0000000..1f91b3a
--- /dev/null
+++ b/common/device-side/nativetesthelper/jni/gtest_wrapper.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <gtest/gtest.h>
+
+static struct {
+    jclass clazz;
+
+    /** static methods **/
+    jmethodID createTestDescription;
+
+    /** methods **/
+    jmethodID addChild;
+} gDescription;
+
+static struct {
+    jclass clazz;
+
+    jmethodID fireTestStarted;
+    jmethodID fireTestIgnored;
+    jmethodID fireTestFailure;
+    jmethodID fireTestFinished;
+
+} gRunNotifier;
+
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} gAssertionFailure;
+
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} gFailure;
+
+jobject gEmptyAnnotationsArray;
+
+static jobject createTestDescription(JNIEnv* env, const char* className, const char* testName) {
+    ScopedLocalRef<jstring> jClassName(env, env->NewStringUTF(className));
+    ScopedLocalRef<jstring> jTestName(env, env->NewStringUTF(testName));
+    return env->CallStaticObjectMethod(gDescription.clazz, gDescription.createTestDescription,
+            jClassName.get(), jTestName.get(), gEmptyAnnotationsArray);
+}
+
+static void addChild(JNIEnv* env, jobject description, jobject childDescription) {
+    env->CallVoidMethod(description, gDescription.addChild, childDescription);
+}
+
+
+class JUnitNotifyingListener : public ::testing::EmptyTestEventListener {
+public:
+
+    JUnitNotifyingListener(JNIEnv* env, jobject runNotifier)
+            : mEnv(env)
+            , mRunNotifier(runNotifier)
+            , mCurrentTestDescription{env, nullptr}
+    {}
+    virtual ~JUnitNotifyingListener() {}
+
+    virtual void OnTestStart(const testing::TestInfo &testInfo) override {
+        mCurrentTestDescription.reset(
+                createTestDescription(mEnv, testInfo.test_case_name(), testInfo.name()));
+        notify(gRunNotifier.fireTestStarted);
+    }
+
+    virtual void OnTestPartResult(const testing::TestPartResult &testPartResult) override {
+        if (!testPartResult.passed()) {
+            char message[1024];
+            snprintf(message, 1024, "%s:%d\n%s", testPartResult.file_name(), testPartResult.line_number(),
+                    testPartResult.message());
+            ScopedLocalRef<jstring> jmessage(mEnv, mEnv->NewStringUTF(message));
+            ScopedLocalRef<jobject> jthrowable(mEnv, mEnv->NewObject(gAssertionFailure.clazz,
+                    gAssertionFailure.ctor, jmessage.get()));
+            ScopedLocalRef<jobject> jfailure(mEnv, mEnv->NewObject(gFailure.clazz,
+                    gFailure.ctor, mCurrentTestDescription.get(), jthrowable.get()));
+            mEnv->CallVoidMethod(mRunNotifier, gRunNotifier.fireTestFailure, jfailure.get());
+        }
+    }
+
+    virtual void OnTestEnd(const testing::TestInfo&) override {
+        notify(gRunNotifier.fireTestFinished);
+        mCurrentTestDescription.reset();
+    }
+
+    virtual void OnTestProgramEnd(const testing::UnitTest& unitTest) override {
+        // Invoke the notifiers for all the disabled tests
+        for (int testCaseIndex = 0; testCaseIndex < unitTest.total_test_case_count(); testCaseIndex++) {
+            auto testCase = unitTest.GetTestCase(testCaseIndex);
+            for (int testIndex = 0; testIndex < testCase->total_test_count(); testIndex++) {
+                auto testInfo = testCase->GetTestInfo(testIndex);
+                if (!testInfo->should_run()) {
+                    mCurrentTestDescription.reset(
+                            createTestDescription(mEnv, testCase->name(), testInfo->name()));
+                    notify(gRunNotifier.fireTestIgnored);
+                    mCurrentTestDescription.reset();
+                }
+            }
+        }
+    }
+
+private:
+    void notify(jmethodID method) {
+        mEnv->CallVoidMethod(mRunNotifier, method, mCurrentTestDescription.get());
+    }
+
+    JNIEnv* mEnv;
+    jobject mRunNotifier;
+    ScopedLocalRef<jobject> mCurrentTestDescription;
+};
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_android_gtestrunner_GtestRunner_nInitialize(JNIEnv *env, jclass, jobject suite) {
+    // Initialize gtest, removing the default result printer
+    int argc = 1;
+    const char* argv[] = { "gtest_wrapper" };
+    ::testing::InitGoogleTest(&argc, (char**) argv);
+
+    auto& listeners = ::testing::UnitTest::GetInstance()->listeners();
+    delete listeners.Release(listeners.default_result_printer());
+
+    gDescription.clazz = (jclass) env->NewGlobalRef(env->FindClass("org/junit/runner/Description"));
+    gDescription.createTestDescription = env->GetStaticMethodID(gDescription.clazz, "createTestDescription",
+            "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/annotation/Annotation;)Lorg/junit/runner/Description;");
+    gDescription.addChild = env->GetMethodID(gDescription.clazz, "addChild",
+            "(Lorg/junit/runner/Description;)V");
+
+    jclass annotations = env->FindClass("java/lang/annotation/Annotation");
+    gEmptyAnnotationsArray = env->NewGlobalRef(env->NewObjectArray(0, annotations, nullptr));
+
+    gAssertionFailure.clazz = (jclass) env->NewGlobalRef(env->FindClass("java/lang/AssertionError"));
+    gAssertionFailure.ctor = env->GetMethodID(gAssertionFailure.clazz, "<init>", "(Ljava/lang/Object;)V");
+
+    gFailure.clazz = (jclass) env->NewGlobalRef(env->FindClass("org/junit/runner/notification/Failure"));
+    gFailure.ctor = env->GetMethodID(gFailure.clazz, "<init>",
+            "(Lorg/junit/runner/Description;Ljava/lang/Throwable;)V");
+
+    gRunNotifier.clazz = (jclass) env->NewGlobalRef(
+            env->FindClass("org/junit/runner/notification/RunNotifier"));
+    gRunNotifier.fireTestStarted = env->GetMethodID(gRunNotifier.clazz, "fireTestStarted",
+            "(Lorg/junit/runner/Description;)V");
+    gRunNotifier.fireTestIgnored = env->GetMethodID(gRunNotifier.clazz, "fireTestIgnored",
+            "(Lorg/junit/runner/Description;)V");
+    gRunNotifier.fireTestFinished = env->GetMethodID(gRunNotifier.clazz, "fireTestFinished",
+            "(Lorg/junit/runner/Description;)V");
+    gRunNotifier.fireTestFailure = env->GetMethodID(gRunNotifier.clazz, "fireTestFailure",
+            "(Lorg/junit/runner/notification/Failure;)V");
+
+    auto unitTest = ::testing::UnitTest::GetInstance();
+    for (int testCaseIndex = 0; testCaseIndex < unitTest->total_test_case_count(); testCaseIndex++) {
+        auto testCase = unitTest->GetTestCase(testCaseIndex);
+        for (int testIndex = 0; testIndex < testCase->total_test_count(); testIndex++) {
+            auto testInfo = testCase->GetTestInfo(testIndex);
+            ScopedLocalRef<jobject> testDescription(env,
+                    createTestDescription(env, testCase->name(), testInfo->name()));
+            addChild(env, suite, testDescription.get());
+        }
+    }
+}
+
+extern "C"
+JNIEXPORT jboolean JNICALL
+Java_com_android_gtestrunner_GtestRunner_nRun(JNIEnv *env, jclass, jobject notifier) {
+    auto& listeners = ::testing::UnitTest::GetInstance()->listeners();
+    JUnitNotifyingListener junitListener{env, notifier};
+    listeners.Append(&junitListener);
+    int success = RUN_ALL_TESTS();
+    listeners.Release(&junitListener);
+    return success == 0;
+}
diff --git a/common/device-side/nativetesthelper/src/com/android/gtestrunner/GtestRunner.java b/common/device-side/nativetesthelper/src/com/android/gtestrunner/GtestRunner.java
new file mode 100644
index 0000000..222a1a0
--- /dev/null
+++ b/common/device-side/nativetesthelper/src/com/android/gtestrunner/GtestRunner.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gtestrunner;
+
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+
+public class GtestRunner extends Runner {
+    private static boolean sOnceFlag = false;
+
+    private Class mTargetClass;
+    private Description mDescription;
+
+    public GtestRunner(Class testClass) {
+        synchronized (GtestRunner.class) {
+            if (sOnceFlag) {
+                throw new IllegalStateException("Error multiple GtestRunners defined");
+            }
+            sOnceFlag = true;
+        }
+
+        mTargetClass = testClass;
+        TargetLibrary library = (TargetLibrary) testClass.getAnnotation(TargetLibrary.class);
+        if (library == null) {
+            throw new IllegalStateException("Missing required @TargetLibrary annotation");
+        }
+        System.loadLibrary(library.value());
+        mDescription = Description.createSuiteDescription(testClass);
+        nInitialize(mDescription);
+    }
+
+    @Override
+    public Description getDescription() {
+        return mDescription;
+    }
+
+    @Override
+    public void run(RunNotifier notifier) {
+        nRun(notifier);
+    }
+
+    private static native void nInitialize(Description description);
+    private static native void nRun(RunNotifier notifier);
+}
diff --git a/common/device-side/nativetesthelper/src/com/android/gtestrunner/TargetLibrary.java b/common/device-side/nativetesthelper/src/com/android/gtestrunner/TargetLibrary.java
new file mode 100644
index 0000000..23bc53d
--- /dev/null
+++ b/common/device-side/nativetesthelper/src/com/android/gtestrunner/TargetLibrary.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gtestrunner;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface TargetLibrary {
+    String value();
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 743f816..f52101b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -62,6 +62,8 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
@@ -82,6 +84,7 @@
     private static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
     private static final String CTS_PREFIX = "cts:";
     private static final String BUILD_INFO = CTS_PREFIX + "build_";
+    private static final String LATEST_LINK_NAME = "latest";
 
     private static final List<String> NOT_RETRY_FILES = Arrays.asList(
             ChecksumReporter.NAME,
@@ -518,6 +521,16 @@
             info("Test Logs: %s", mLogDir.getCanonicalPath());
             debug("Full Result: %s", zippedResults.getCanonicalPath());
 
+            Path latestLink = createLatestLinkDirectory(mResultDir.toPath());
+            if (latestLink != null) {
+                info("Latest results link: " + latestLink.toAbsolutePath());
+            }
+
+            latestLink = createLatestLinkDirectory(mLogDir.toPath());
+            if (latestLink != null) {
+                info("Latest logs link: " + latestLink.toAbsolutePath());
+            }
+
             saveLog(resultFile, zippedResults);
 
             uploadResult(resultFile);
@@ -534,6 +547,30 @@
                 moduleProgress);
     }
 
+    private Path createLatestLinkDirectory(Path directory) {
+        Path link = null;
+
+        Path parent = directory.getParent();
+
+        if (parent != null) {
+            link = parent.resolve(LATEST_LINK_NAME);
+            try {
+                // if latest already exists, we have to remove it before creating
+                Files.deleteIfExists(link);
+                Files.createSymbolicLink(link, directory);
+            } catch (IOException ioe) {
+                CLog.e("Exception while attempting to create 'latest' link to: [%s]",
+                    directory);
+                CLog.e(ioe);
+                return null;
+            } catch (UnsupportedOperationException uoe) {
+                CLog.e("Failed to create 'latest' symbolic link - unsupported operation");
+                return null;
+            }
+        }
+        return link;
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/error_prone_rules_tests.mk b/error_prone_rules_tests.mk
index d17828d..7c729ec 100644
--- a/error_prone_rules_tests.mk
+++ b/error_prone_rules_tests.mk
@@ -17,9 +17,13 @@
 # Goal is to eventually merge with error_prone_rules.mk
 LOCAL_ERROR_PRONE_FLAGS:= -Xep:ArrayToString:ERROR \
                           -Xep:CollectionIncompatibleType:ERROR \
+                          -Xep:EqualsIncompatibleType:ERROR \
                           -Xep:EqualsNaN:ERROR \
                           -Xep:FormatString:ERROR \
+                          -Xep:IdentityBinaryExpression:ERROR \
                           -Xep:JUnit3TestNotRun:ERROR \
+                          -Xep:JUnitAmbiguousTestClass:ERROR \
+                          -Xep:MissingFail:ERROR \
                           -Xep:SizeGreaterThanOrEqualsZero:ERROR \
                           -Xep:TryFailThrowable:ERROR
 
diff --git a/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
index 3f2ffa8..75ffc85 100644
--- a/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
+++ b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
@@ -33,8 +33,8 @@
  */
 public class TestDeviceStressTest extends DeviceTestCase {
 
-    private static final int TEST_FILE_COUNT= 200;
-    private int mIterations = 25;
+    private static final int TEST_FILE_COUNT= 100;
+    private int mIterations = 20;
     private ITestDevice mTestDevice;
 
     @Override
diff --git a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
index 1f5d669..591dcb4 100644
--- a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
+++ b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
@@ -274,19 +274,15 @@
         executePush(apkFile.getAbsolutePath(), targetPathApk, targetDir);
         assertTrue("Failed to push APK from ", doesFileExist(targetPathApk));
         // Run profman to create the real profile on device.
-        try {
-            String pathSpec = executeSuShellAdbCommand(1, "pm", "path", APPLICATION_PACKAGE)[0];
-            pathSpec = pathSpec.replace("package:", "");
-            assertTrue("Failed find APK " + pathSpec, doesFileExist(pathSpec));
-            executeSuShellAdbCommand(
+        String pathSpec = executeSuShellAdbCommand(1, "pm", "path", APPLICATION_PACKAGE)[0];
+        pathSpec = pathSpec.replace("package:", "");
+        assertTrue("Failed find APK " + pathSpec, doesFileExist(pathSpec));
+        executeSuShellAdbCommand(
                 "profman",
                 "--create-profile-from=" + targetPathTemp,
                 "--apk=" + pathSpec,
                 "--dex-location=" + pathSpec,
                 "--reference-profile-file=" + targetPath);
-        } catch (Exception e) {
-            assertEquals("", e.toString());
-        }
         executeSuShellAdbCommand(0, "chown", owner, targetPath);
         // Verify that the file was written successfully
         assertTrue("failed to create profile file", doesFileExist(targetPath));
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
index bc8d3d3..938ee07 100644
--- a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearApplicationDataTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearApplicationDataTest.java
new file mode 100644
index 0000000..d477706
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearApplicationDataTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test class that calls DPM.clearApplicationUserData and verifies that it doesn't time out.
+ */
+public class ClearApplicationDataTest extends BaseDeviceAdminTest {
+    private static final String TEST_PKG = "com.android.cts.intent.receiver";
+    private static final Semaphore mSemaphore = new Semaphore(0);
+    private static final long CLEAR_APPLICATION_DATA_TIMEOUT_S = 10;
+
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mHandlerThread = new HandlerThread("ClearApplicationData");
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mHandlerThread.quitSafely();
+        super.tearDown();
+    }
+
+    public void testClearApplicationData() throws Exception {
+        mDevicePolicyManager.clearApplicationUserData(ADMIN_RECEIVER_COMPONENT, TEST_PKG,
+                (String pkg, boolean succeeded) -> {
+                    assertEquals(TEST_PKG, pkg);
+                    assertTrue(succeeded);
+                    mSemaphore.release();
+                }, mHandler);
+
+        assertTrue("Clearing application data took too long",
+                mSemaphore.tryAcquire(CLEAR_APPLICATION_DATA_TIMEOUT_S, TimeUnit.SECONDS));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index 6c706ee..70a5d09 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.os.UserManager;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.UiDevice;
@@ -47,6 +46,7 @@
     private static final String SIMPLE_PRE_M_APP_PACKAGE_NAME =
             "com.android.cts.launcherapps.simplepremapp";
     private static final String PERMISSION_NAME = "android.permission.READ_CONTACTS";
+    private static final String DEVELOPMENT_PERMISSION = "android.permission.INTERACT_ACROSS_USERS";
 
     private static final String PERMISSIONS_ACTIVITY_NAME
             = PERMISSION_APP_PACKAGE_NAME + ".PermissionActivity";
@@ -227,6 +227,15 @@
         assertSetPermissionGrantStatePreMApp(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
     }
 
+    public void testPermissionGrantState_developmentPermission() throws Exception {
+        assertFailedToSetDevelopmentPermissionGrantState(
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+        assertFailedToSetDevelopmentPermissionGrantState(
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        assertFailedToSetDevelopmentPermissionGrantState(
+                DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+    }
+
     private void assertPermissionRequest(int expected) throws Exception {
         assertPermissionRequest(expected, null);
     }
@@ -274,6 +283,18 @@
                 value);
     }
 
+    private void assertFailedToSetDevelopmentPermissionGrantState(int value) throws Exception {
+        assertFalse(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                PERMISSION_APP_PACKAGE_NAME, DEVELOPMENT_PERMISSION, value));
+        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                PERMISSION_APP_PACKAGE_NAME, DEVELOPMENT_PERMISSION),
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        assertEquals(mPackageManager.checkPermission(DEVELOPMENT_PERMISSION,
+                PERMISSION_APP_PACKAGE_NAME),
+                PackageManager.PERMISSION_DENIED);
+    }
+
+
     private void assertSetPermissionGrantStatePreMApp(int value) throws Exception {
         assertFalse(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
                 SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME,
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index 4cc041a..4084099 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -22,7 +22,10 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
 
 LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt cts-junit
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index 9a09007..f2f49f9 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -52,6 +52,20 @@
                 <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
             </intent-filter>
         </receiver>
+        <receiver
+                android:name="com.android.cts.deviceowner.CreateAndManageUserTest$SecondaryUserAdminReceiver"
+                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>
+
+        <service android:name="com.android.cts.deviceowner.CreateAndManageUserTest$PrimaryUserService"
+                 android:exported="true"
+                 android:permission="android.permission.BIND_DEVICE_ADMIN">
+        </service>
 
         <activity
             android:name="com.android.cts.deviceowner.KeyManagementActivity"
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index a540c27..5e32d3e 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -17,6 +17,7 @@
 package com.android.cts.deviceowner;
 
 import android.app.ActivityManager;
+import android.app.Service;
 import android.app.admin.DeviceAdminReceiver;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -24,16 +25,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.os.Bundle;
+import android.os.IBinder;
 import android.os.PersistableBundle;
-import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
+
 import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -50,6 +56,12 @@
     private static final String SETUP_COMPLETE_EXTRA = "setupCompleteExtra";
     private static final int BROADCAST_TIMEOUT = 15_000;
     private static final int USER_SWITCH_DELAY = 10_000;
+
+    private static final String AFFILIATION_ID = "affiliation.id";
+    private static final String EXTRA_AFFILIATION_ID = "affiliationIdExtra";
+    private static final long ON_ENABLED_TIMEOUT_SECONDS = 120;
+
+
     private PackageManager mPackageManager;
     private ActivityManager mActivityManager;
     private volatile boolean mReceived;
@@ -302,6 +314,28 @@
         }
     }
 
+    public void testCreateAndManageUser_StartUserInBackground() throws Exception {
+        String testUserName = "TestUser_" + System.currentTimeMillis();
+
+        // Set affiliation id to allow communication
+        mDevicePolicyManager.setAffiliationIds(getWho(), Collections.singleton(AFFILIATION_ID));
+
+        // Pack the affiliation id in a bundle so the secondary user can get it
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(EXTRA_AFFILIATION_ID, AFFILIATION_ID);
+
+        // Do not assign return value to mUserHandle, so it is not removed in tearDown.
+        UserHandle uh = mDevicePolicyManager.createAndManageUser(
+                getWho(),
+                testUserName,
+                SecondaryUserAdminReceiver.getComponentName(mContext),
+                bundle,
+                DevicePolicyManager.START_USER_IN_BACKGROUND);
+        Log.d(TAG, "User create: " + uh);
+
+        PrimaryUserService.assertCrossUserCallArrived();
+    }
+
     static class LocalBroadcastReceiver extends BroadcastReceiver {
         private SynchronousQueue<UserHandle> mQueue = new SynchronousQueue<UserHandle>();
 
@@ -318,4 +352,75 @@
             return mQueue.poll(BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS);
         }
     }
+
+    public static final class PrimaryUserService extends Service {
+        private static final Semaphore mSemaphore = new Semaphore(0);
+
+        private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() {
+            public void onEnabledCalled() {
+                Log.d(TAG, "onEnabledCalled on primary user");
+                mSemaphore.release();
+            }
+        };
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return mBinder;
+        }
+
+        static void assertCrossUserCallArrived() throws Exception {
+            assertTrue(mSemaphore.tryAcquire(ON_ENABLED_TIMEOUT_SECONDS, TimeUnit.SECONDS));
+        }
+    }
+
+    public static final class SecondaryUserAdminReceiver extends DeviceAdminReceiver {
+        @Override
+        public void onEnabled(Context context, Intent intent) {
+            Log.d(TAG, "onEnabled called");
+            DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+            // Set affiliation ids
+            String affiliationId = intent.getStringExtra(EXTRA_AFFILIATION_ID);
+            dpm.setAffiliationIds(getComponentName(context),
+                    Collections.singleton(affiliationId));
+            // Call all affiliated users
+            final List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(
+                    getComponentName(context));
+            assertEquals(1, targetUsers.size());
+            pingTargetUser(context, dpm, targetUsers.get(0));
+        }
+
+        private void pingTargetUser(Context context, DevicePolicyManager dpm, UserHandle target) {
+            Log.d(TAG, "Pinging target: " + target);
+            final ServiceConnection serviceConnection = new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                    Log.d(TAG, "onServiceConnected is called in " + Thread.currentThread().getName());
+                    ICrossUserService crossUserService = ICrossUserService
+                            .Stub.asInterface(service);
+                    try {
+                        crossUserService.onEnabledCalled();
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Error when calling primary user", re);
+                        // Do nothing, primary user will time out
+                    }
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    Log.d(TAG, "onServiceDisconnected is called");
+                }
+            };
+            final Intent serviceIntent = new Intent(context, PrimaryUserService.class);
+            assertTrue(dpm.bindDeviceAdminServiceAsUser(
+                    getComponentName(context),
+                    serviceIntent,
+                    serviceConnection,
+                    Context.BIND_AUTO_CREATE,
+                    target));
+        }
+
+        public static ComponentName getComponentName(Context context) {
+            return new ComponentName(context, SecondaryUserAdminReceiver.class);
+        }
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ICrossUserService.aidl b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ICrossUserService.aidl
new file mode 100644
index 0000000..0cf5dcf
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ICrossUserService.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceowner;
+
+interface ICrossUserService {
+    void onEnabledCalled();
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/ClearApplicationDataTest.java b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/ClearApplicationDataTest.java
new file mode 100644
index 0000000..0d2a990
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/ClearApplicationDataTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.intent.receiver;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class that writes to shared preference and verifies that the shared preference gets cleared
+ * after DPM.clearApplicationUserData was called.
+ */
+@SmallTest
+public class ClearApplicationDataTest {
+    private static final String SHARED_PREFERENCE_NAME = "test-preference";
+    private static final String I_WAS_HERE = "I-Was-Here";
+
+    private Context mContext;
+    private SharedPreferences mSharedPrefs;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mSharedPrefs = mContext.getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
+    }
+
+    @Test
+    public void testWriteToSharedPreference() {
+        mSharedPrefs.edit().putBoolean(I_WAS_HERE, true).commit();
+        assertTrue(mSharedPrefs.contains(I_WAS_HERE));
+    }
+
+    @Test
+    public void testSharedPreferenceCleared() {
+        assertFalse(mSharedPrefs.contains(I_WAS_HERE));
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 70ee0d9..9d66b93 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -138,6 +138,8 @@
         removeTestUsers();
         // Unlock keyguard before test
         wakeupAndDismissKeyguard();
+        // Go to home.
+        executeShellCommand("input keyevent KEYCODE_HOME");
     }
 
     @Override
@@ -256,6 +258,7 @@
 
     protected void removeUser(int userId) throws Exception  {
         if (listUsers().contains(userId) && userId != USER_SYSTEM) {
+            waitForBroadcastIdle();
             // Don't log output, as tests sometimes set no debug user restriction, which
             // causes this to fail, we should still continue and remove the user.
             String stopUserCommand = "am stop-user -w -f " + userId;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index b660959..ebccc1d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -253,6 +253,15 @@
         executeDeviceTestMethod(".PermissionsTest", "testPermissionGrantState");
     }
 
+    public void testPermissionGrant_developmentPermission() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installAppPermissionAppAsUser();
+        executeDeviceTestMethod(
+                ".PermissionsTest", "testPermissionGrantState_developmentPermission");
+    }
+
     /**
      * Require a device for tests that use the network stack. Headless Androids running in
      * data centres might need their network rules un-tampered-with in order to keep the ADB / VNC
@@ -807,6 +816,18 @@
                 Collections.singletonMap(ARG_ALLOW_FAILURE, Boolean.toString(allowFailures)));
     }
 
+    public void testClearApplicationData() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installAppAsUser(INTENT_RECEIVER_APK, mUserId);
+        runDeviceTestsAsUser(INTENT_RECEIVER_PKG, INTENT_RECEIVER_PKG + ".ClearApplicationDataTest",
+                "testWriteToSharedPreference", mUserId);
+        executeDeviceTestMethod(".ClearApplicationDataTest", "testClearApplicationData");
+        runDeviceTestsAsUser(INTENT_RECEIVER_PKG, INTENT_RECEIVER_PKG + ".ClearApplicationDataTest",
+                "testSharedPreferenceCleared", mUserId);
+    }
+
     protected void executeDeviceTestClass(String className) throws Exception {
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId);
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index a4844f5..ba0dcc0 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -46,14 +46,14 @@
     private static final String DEVICE_OWNER_COMPONENT = DEVICE_OWNER_PKG + "/"
             + ADMIN_RECEIVER_TEST_CLASS;
 
-    /** The ephemeral users are implemented and supported on the device. */
-    private boolean mHasEphemeralUserFeature;
+    /** Forcing ephemeral users is implemented and supported on the device. */
+    private boolean mHasForceEphemeralUserFeature;
 
     /**
-     * Ephemeral users are implemented, but unsupported on the device (because of missing split
-     * system user).
+     * Force ephemeral users feature is implemented, but unsupported on the device (because of
+     * missing split system user).
      */
-    private boolean mHasDisabledEphemeralUserFeature;
+    private boolean mHasDisabledForceEphemeralUserFeature;
 
     @Override
     protected void setUp() throws Exception {
@@ -67,9 +67,10 @@
                 fail("Failed to set device owner");
             }
         }
-        mHasEphemeralUserFeature = mHasFeature && canCreateAdditionalUsers(1) && hasUserSplit();
-        mHasDisabledEphemeralUserFeature =
-                mHasFeature && canCreateAdditionalUsers(1) && !hasUserSplit();
+        mHasForceEphemeralUserFeature = mHasFeature && canCreateAdditionalUsers(1)
+                && hasUserSplit();
+        mHasDisabledForceEphemeralUserFeature = mHasFeature && canCreateAdditionalUsers(1)
+                && !hasUserSplit();
     }
 
     @Override
@@ -125,7 +126,7 @@
 
     /** Tries to toggle the force-ephemeral-users on and checks it was really set. */
     public void testSetForceEphemeralUsers() throws Exception {
-        if (!mHasEphemeralUserFeature) {
+        if (!mHasForceEphemeralUserFeature) {
             return;
         }
         // Set force-ephemeral-users policy and verify it was set.
@@ -136,7 +137,7 @@
      * Setting force-ephemeral-users policy to true without a split system user should fail.
      */
     public void testSetForceEphemeralUsersFailsWithoutSplitSystemUser() throws Exception {
-        if (mHasDisabledEphemeralUserFeature) {
+        if (mHasDisabledForceEphemeralUserFeature) {
             executeDeviceTestMethod(".ForceEphemeralUsersTest", "testSetForceEphemeralUsersFails");
         }
     }
@@ -148,7 +149,7 @@
      * <p>If the current user is the system user, the other users are removed straight away.
      */
     public void testRemoveUsersOnSetForceEphemeralUsers() throws Exception {
-        if (!mHasEphemeralUserFeature) {
+        if (!mHasForceEphemeralUserFeature) {
             return;
         }
 
@@ -171,7 +172,7 @@
      * before all other users are removed.
      */
     public void testRemoveUsersOnSetForceEphemeralUsersWithUserSwitch() throws Exception {
-        if (!mHasEphemeralUserFeature) {
+        if (!mHasForceEphemeralUserFeature) {
             return;
         }
 
@@ -206,7 +207,7 @@
 
     /** The users created after setting force-ephemeral-users policy to true must be ephemeral. */
     public void testCreateUserAfterSetForceEphemeralUsers() throws Exception {
-        if (!mHasEphemeralUserFeature) {
+        if (!mHasForceEphemeralUserFeature) {
             return;
         }
 
@@ -221,7 +222,7 @@
      * Test creating an epehemeral user using the DevicePolicyManager's createAndManageUser method.
      */
     public void testCreateAndManageEphemeralUser() throws Exception {
-        if (!mHasEphemeralUserFeature) {
+        if (!mHasFeature || !canCreateAdditionalUsers(1)) {
             return;
         }
 
@@ -236,17 +237,6 @@
         assertEquals("Ephemeral flag must be set", FLAG_EPHEMERAL, flags & FLAG_EPHEMERAL);
     }
 
-    /**
-     * Test that creating an epehemeral user using the DevicePolicyManager's createAndManageUser
-     * method fails on systems without the split system user.
-     */
-    public void testCreateAndManageEphemeralUserFailsWithoutSplitSystemUser() throws Exception {
-        if (mHasDisabledEphemeralUserFeature) {
-            executeDeviceTestMethod(
-                    ".CreateAndManageUserTest", "testCreateAndManageEphemeralUserFails");
-        }
-    }
-
 // Disabled due to b/29072728
 //    public void testCreateAndManageUser_SkipSetupWizard() throws Exception {
 //        if (mHasCreateAndManageUserFeature) {
@@ -276,6 +266,13 @@
         }
     }
 
+    public void testCreateAndManageUser_StartUserInBackground() throws Exception {
+        if (mHasFeature && canCreateAdditionalUsers(1)) {
+            executeDeviceTestMethod(".CreateAndManageUserTest",
+                    "testCreateAndManageUser_StartUserInBackground");
+        }
+    }
+
     public void testUserAddedOrRemovedBroadcasts() throws Exception {
         if (mHasFeature && canCreateAdditionalUsers(1)) {
             executeDeviceTestMethod(".CreateAndManageUserTest",
@@ -440,6 +437,7 @@
         setProfileOwnerOrFail(DEVICE_OWNER_COMPONENT, userId);
 
         switchUser(userId);
+        wakeupAndDismissKeyguard();
 
         // Setting the same affiliation ids on both users and running the lock task tests.
         runDeviceTestsAsUser(
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
index df4a47c..84bdd7d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
@@ -17,7 +17,7 @@
 package com.android.cts.devicepolicy;
 
 /**
- * Tests for emphemeral users and profiles.
+ * Tests for ephemeral users and profiles.
  */
 public class EphemeralUserTest extends BaseDevicePolicyTest {
 
@@ -35,7 +35,7 @@
 
     /** The user should have the ephemeral flag set if it was created as ephemeral. */
     public void testCreateEphemeralUser() throws Exception {
-        if (!mHasFeature || !hasUserSplit()) {
+        if (!mHasFeature) {
             return;
         }
         int userId = createUser(FLAG_EPHEMERAL);
@@ -59,7 +59,8 @@
      */
     public void testProfileInheritsEphemeral() throws Exception {
         if (!mHasFeature || !hasDeviceFeature("android.software.managed_users")
-                || !hasUserSplit() || !canCreateAdditionalUsers(2)) {
+                || !canCreateAdditionalUsers(2)
+                || !hasUserSplit()) {
             return;
         }
         int userId = createUser(FLAG_EPHEMERAL);
@@ -72,7 +73,7 @@
      * Ephemeral user should be automatically removed after it is stopped.
      */
     public void testRemoveEphemeralOnStop() throws Exception {
-        if (!mHasFeature || !hasUserSplit()) {
+        if (!mHasFeature) {
             return;
         }
         int userId = createUser(FLAG_EPHEMERAL);
@@ -87,7 +88,7 @@
      * and not ephemeral when the feature is not set.
      */
     public void testEphemeralGuestFeature() throws Exception {
-        if (!mHasFeature || !hasUserSplit()) {
+        if (!mHasFeature) {
             return;
         }
         // Create a guest user.
@@ -103,20 +104,6 @@
         }
     }
 
-    /**
-     * Test that creating an ephemeral user fails on systems without the split system user.
-     */
-    public void testCreateEphemeralWithoutUserSplitFails() throws Exception {
-        if (!mHasFeature || hasUserSplit()) {
-            return;
-        }
-        String command ="pm create-user --ephemeral " + "TestUser_" + System.currentTimeMillis();
-        String commandOutput = getDevice().executeShellCommand(command);
-
-        assertEquals("Creating the epehemeral user should fail.",
-                "Error: couldn't create User.", commandOutput.trim());
-    }
-
     private boolean getGuestUsersEphemeral() throws Exception {
         String commandOutput = getDevice().executeShellCommand("dumpsys user");
         String[] outputLines = commandOutput.split("\n");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java
index ef7099b..b71c4c87 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java
@@ -15,8 +15,6 @@
  */
 package com.android.cts.devicepolicy;
 
-import org.junit.Test;
-
 /**
  * This class tests the provisioning flow with an APK that declares a single receiver with
  * BIND_DEVICE_ADMIN permissions, which was a requirement for the app sending the
@@ -54,7 +52,6 @@
         super.tearDown();
     }
 
-    @Test
     public void testEXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME() throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/incident/src/com/android/server/cts/PrintProtoTest.java b/hostsidetests/incident/src/com/android/server/cts/PrintProtoTest.java
new file mode 100644
index 0000000..24f3d2a
--- /dev/null
+++ b/hostsidetests/incident/src/com/android/server/cts/PrintProtoTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.cts;
+
+import android.service.print.PrintServiceDumpProto;
+import android.service.print.PrintSpoolerStateProto;
+import android.service.print.PrintUserStateProto;
+
+import com.android.tradefed.log.LogUtil;
+
+/**
+ * Test proto dump of print
+ */
+public class PrintProtoTest extends ProtoDumpTestCase {
+    /**
+     * Test that print dump is reasonable
+     *
+     * @throws Exception
+     */
+    public void testDump() throws Exception {
+        // If the device doesn't support printing, then pass.
+        if (!getDevice().hasFeature("android.software.print")) {
+            LogUtil.CLog.d("Bypass as android.software.print is not supported.");
+            return;
+        }
+
+        PrintServiceDumpProto dump = getDump(PrintServiceDumpProto.parser(),
+                "dumpsys print --proto");
+
+        assertTrue(dump.getUserStatesCount() > 0);
+
+        PrintUserStateProto userState = dump.getUserStatesList().get(0);
+        assertEquals(0, userState.getUserId());
+    }
+}
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
index 3c1f14e..e7be900 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
@@ -140,6 +140,8 @@
         instrTest.addIncludeFilter(fullTestName);
         instrTest.setTestTimeout(testTimeout);
         instrTest.setShellTimeout(shellTimeout);
+        // disable rerun mode to avoid collecting tests first then running.
+        instrTest.setRerunMode(false);
         for (Entry<String, String> e : getArgs().entrySet()) {
             instrTest.addInstrumentationArg(e.getKey(), e.getValue());
         }
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index d2c0873..133a43b 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -127,6 +127,19 @@
         assertBackgroundNetworkAccess(false);
     }
 
+    public void testBackgroundNetworkAccess_tempWhitelisted() throws Exception {
+        if (!isSupported()) return;
+
+        setAppIdle(true);
+        assertBackgroundNetworkAccess(false);
+
+        addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+        assertBackgroundNetworkAccess(true);
+        // Wait until the whitelist duration is expired.
+        SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+        assertBackgroundNetworkAccess(false);
+    }
+
     public void testBackgroundNetworkAccess_disabled() throws Exception {
         if (!isSupported()) return;
 
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index e65db31..bd43cc8 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -107,6 +107,8 @@
 
     private static final String APP_NOT_FOREGROUND_ERROR = "app_not_fg";
 
+    protected static final long TEMP_POWERSAVE_WHITELIST_DURATION_MS = 5_000; // 5 sec
+
     protected Context mContext;
     protected Instrumentation mInstrumentation;
     protected ConnectivityManager mCm;
@@ -706,6 +708,12 @@
                 + ". Full list: " + uids);
     }
 
+    protected void addTempPowerSaveModeWhitelist(String packageName, long duration)
+            throws Exception {
+        Log.i(TAG, "Adding pkg " + packageName + " to temp-power-save-mode whitelist");
+        executeShellCommand("dumpsys deviceidle tempwhitelist -d " + duration + " " + packageName);
+    }
+
     protected void assertPowerSaveModeWhitelist(String packageName, boolean expected)
             throws Exception {
         // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
index 5248255..76332be 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.cts.net.hostside;
 
+import android.os.SystemClock;
 import android.util.Log;
 
 /**
@@ -271,4 +272,55 @@
             setDozeMode(false);
         }
     }
+
+    public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception {
+        if (!isSupported()) {
+            return;
+        }
+        if (!isDozeModeEnabled()) {
+            Log.i(TAG, "Skipping " + getClass() + "." + getName()
+                    + "() because device does not support Doze Mode");
+            return;
+        }
+
+        setDozeMode(true);
+        setAppIdle(true);
+
+        try {
+            assertBackgroundNetworkAccess(false);
+
+            addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(true);
+
+            // Wait until the whitelist duration is expired.
+            SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(false);
+        } finally {
+            setAppIdle(false);
+            setDozeMode(false);
+        }
+    }
+
+    public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception {
+        if (!isSupported()) {
+            return;
+        }
+
+        setBatterySaverMode(true);
+        setAppIdle(true);
+
+        try {
+            assertBackgroundNetworkAccess(false);
+
+            addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(true);
+
+            // Wait until the whitelist duration is expired.
+            SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(false);
+        } finally {
+            setAppIdle(false);
+            setBatterySaverMode(false);
+        }
+    }
 }
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index bf3fc08..fe9d36c 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -146,6 +146,11 @@
                 "testBackgroundNetworkAccess_whitelisted");
     }
 
+    public void testAppIdleMetered_tempWhitelisted() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+                "testBackgroundNetworkAccess_tempWhitelisted");
+    }
+
     public void testAppIdleMetered_enabled() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
                 "testBackgroundNetworkAccess_enabled");
@@ -166,6 +171,11 @@
                 "testBackgroundNetworkAccess_whitelisted");
     }
 
+    public void testAppIdleNonMetered_tempWhitelisted() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+                "testBackgroundNetworkAccess_tempWhitelisted");
+    }
+
     public void testAppIdleNonMetered_enabled() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
                 "testBackgroundNetworkAccess_enabled");
@@ -261,6 +271,16 @@
                 "testDozeAndAppIdle_powerSaveWhitelists");
     }
 
+    public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+                "testAppIdleAndDoze_tempPowerSaveWhitelists");
+    }
+
+    public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+                "testAppIdleAndBatterySaver_tempPowerSaveWhitelists");
+    }
+
     /*******************
      * Helper methods. *
      *******************/
diff --git a/hostsidetests/security/securityPatch/Bug-33039685/Android.mk b/hostsidetests/security/securityPatch/Bug-33039685/Android.mk
index 701138d..17af326 100644
--- a/hostsidetests/security/securityPatch/Bug-33039685/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-33039685/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-33299365/Android.mk b/hostsidetests/security/securityPatch/Bug-33299365/Android.mk
index 8a7b047..6ba7ed9 100644
--- a/hostsidetests/security/securityPatch/Bug-33299365/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-33299365/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-34173755/Android.mk b/hostsidetests/security/securityPatch/Bug-34173755/Android.mk
index f07cf4e..a64a37c 100644
--- a/hostsidetests/security/securityPatch/Bug-34173755/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-34173755/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-34624155/Android.mk b/hostsidetests/security/securityPatch/Bug-34624155/Android.mk
index 0f1a737..95e8c24 100644
--- a/hostsidetests/security/securityPatch/Bug-34624155/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-34624155/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35139833/Android.mk b/hostsidetests/security/securityPatch/Bug-35139833/Android.mk
index 8865fa9..bc49a79 100644
--- a/hostsidetests/security/securityPatch/Bug-35139833/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35139833/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35468048/Android.mk b/hostsidetests/security/securityPatch/Bug-35468048/Android.mk
index 9213fa3..88166b8 100644
--- a/hostsidetests/security/securityPatch/Bug-35468048/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35468048/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35470735/Android.mk b/hostsidetests/security/securityPatch/Bug-35470735/Android.mk
index 1f14c2c..1a42fd2 100644
--- a/hostsidetests/security/securityPatch/Bug-35470735/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35470735/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35644510/Android.mk b/hostsidetests/security/securityPatch/Bug-35644510/Android.mk
index efe00f2..3a8edf6 100644
--- a/hostsidetests/security/securityPatch/Bug-35644510/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35644510/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64

 

 # Tag this module as a cts test artifact

-LOCAL_COMPATIBILITY_SUITE := cts

+LOCAL_COMPATIBILITY_SUITE := cts vts

 LOCAL_CTS_TEST_PACKAGE := android.security.cts

 

 LOCAL_ARM_MODE := arm

diff --git a/hostsidetests/security/securityPatch/Bug-35676417/Android.mk b/hostsidetests/security/securityPatch/Bug-35676417/Android.mk
index 41ba50d..06ab345 100644
--- a/hostsidetests/security/securityPatch/Bug-35676417/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35676417/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35764875/Android.mk b/hostsidetests/security/securityPatch/Bug-35764875/Android.mk
index e62bdd2..4d6f4fc 100644
--- a/hostsidetests/security/securityPatch/Bug-35764875/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35764875/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64

 

 # Tag this module as a cts test artifact

-LOCAL_COMPATIBILITY_SUITE := cts

+LOCAL_COMPATIBILITY_SUITE := cts vts

 LOCAL_CTS_TEST_PACKAGE := android.security.cts

 

 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/

diff --git a/hostsidetests/security/securityPatch/Bug-35950388/Android.mk b/hostsidetests/security/securityPatch/Bug-35950388/Android.mk
index 824e86f..8289311 100644
--- a/hostsidetests/security/securityPatch/Bug-35950388/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35950388/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64

 

 # Tag this module as a cts test artifact

-LOCAL_COMPATIBILITY_SUITE := cts

+LOCAL_COMPATIBILITY_SUITE := cts vts

 LOCAL_CTS_TEST_PACKAGE := android.security.cts

 LOCAL_C_INCLUDES += include

 LOCAL_ARM_MODE := arm

diff --git a/hostsidetests/security/securityPatch/Bug-35950805/Android.mk b/hostsidetests/security/securityPatch/Bug-35950805/Android.mk
index 11c4e46..b3dec07 100644
--- a/hostsidetests/security/securityPatch/Bug-35950805/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35950805/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk
index 0a5b344..f4f2c57 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk
index fa5539b..f3ab0d6 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/services/activityandwindowmanager/util/Android.mk b/hostsidetests/services/activityandwindowmanager/util/Android.mk
index 993ba94..ec07ac6 100644
--- a/hostsidetests/services/activityandwindowmanager/util/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/util/Android.mk
@@ -23,7 +23,9 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed host-libprotobuf-java-full
+
+LOCAL_STATIC_JAVA_LIBRARIES := platformprotos
 
 LOCAL_MODULE := cts-amwm-util
 
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index 0cdf13e..6be01ec 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -20,11 +20,27 @@
 import static android.server.cts.StateLogger.log;
 import static android.server.cts.StateLogger.logE;
 
-import com.android.tradefed.device.CollectingOutputReceiver;
-import com.android.tradefed.device.DeviceNotAvailableException;
+import android.graphics.RectProto;
+import com.android.server.wm.proto.AppWindowTokenProto;
+import com.android.server.wm.proto.AppTransitionProto;
+import com.android.server.wm.proto.DisplayProto;
+import com.android.server.wm.proto.IdentifierProto;
+import com.android.server.wm.proto.PinnedStackControllerProto;
+import com.android.server.wm.proto.StackProto;
+import com.android.server.wm.proto.TaskProto;
+import com.android.server.wm.proto.WindowManagerServiceProto;
+import com.android.server.wm.proto.WindowStateAnimatorProto;
+import com.android.server.wm.proto.WindowStateProto;
+import com.android.server.wm.proto.WindowSurfaceControllerProto;
+import com.android.server.wm.proto.WindowTokenProto;
+import android.view.DisplayInfoProto;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
 import com.android.tradefed.device.ITestDevice;
 
-import java.awt.*;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import java.awt.Rectangle;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -32,8 +48,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 public class WindowManagerState {
 
@@ -55,63 +69,10 @@
 
     public static final String APP_STATE_IDLE = "APP_STATE_IDLE";
 
-    private static final String DUMPSYS_WINDOW = "dumpsys window -a";
+    private static final String DUMPSYS_WINDOW = "dumpsys window -a --proto";
 
-    private static final Pattern sWindowPattern =
-            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+)\\}\\:");
-    private static final Pattern sStartingWindowPattern =
-            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Starting (.+)\\}\\:");
-    private static final Pattern sExitingWindowPattern =
-            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+) EXITING\\}\\:");
-    private static final Pattern sDebuggerWindowPattern =
-            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger: (.+)\\}\\:");
-
-    private static final Pattern sFocusedWindowPattern = Pattern.compile(
-            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) (\\S+)\\}");
-    private static final Pattern sAppErrorFocusedWindowPattern = Pattern.compile(
-            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Application Error\\: (\\S+)\\}");
-    private static final Pattern sWaitingForDebuggerFocusedWindowPattern = Pattern.compile(
-            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger\\: (\\S+)\\}");
-
-    private static final Pattern sFocusedAppPattern =
-            Pattern.compile("mFocusedApp=AppWindowToken\\{(.+) token=Token\\{(.+) "
-                    + "ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)");
-    private static final Pattern sStableBoundsPattern = Pattern.compile(
-            "mStable=\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\)");
-    private static final Pattern sDefaultPinnedStackBoundsPattern = Pattern.compile(
-            "defaultBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
-    private static final Pattern sPinnedStackMovementBoundsPattern = Pattern.compile(
-            "movementBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
-    private static final Pattern sRotationPattern = Pattern.compile(
-            "mRotation=(\\d).*");
-    private static final Pattern sLastOrientationPattern = Pattern.compile(
-            ".*mLastOrientation=(\\d)");
-
-    private static final Pattern sLastAppTransitionPattern =
-            Pattern.compile("mLastUsedAppTransition=(.+)");
-    private static final Pattern sAppTransitionStatePattern =
-            Pattern.compile("mAppTransitionState=(.+)");
-
-    private static final Pattern sStackIdPattern = Pattern.compile("mStackId=(\\d+)");
-
-    private static final Pattern sInputMethodWindowPattern =
-            Pattern.compile("mInputMethodWindow=Window\\{([0-9a-fA-F]+) u\\d+ .+\\}.*");
-
-    private static final Pattern sDisplayIdPattern =
-            Pattern.compile("Display: mDisplayId=(\\d+)");
-
-    private static final Pattern sDisplayFrozenPattern =
-            Pattern.compile("mDisplayFrozen=([a-z]*) .*");
-
-    private static final Pattern sDockedStackMinimizedPattern =
-            Pattern.compile("mMinimizedDock=([a-z]*)");
-
-    private static final Pattern[] sExtractStackExitPatterns = {
-            sStackIdPattern, sWindowPattern, sStartingWindowPattern, sExitingWindowPattern,
-            sDebuggerWindowPattern, sFocusedWindowPattern, sAppErrorFocusedWindowPattern,
-            sWaitingForDebuggerFocusedWindowPattern,
-            sFocusedAppPattern, sLastAppTransitionPattern, sDefaultPinnedStackBoundsPattern,
-            sPinnedStackMovementBoundsPattern, sDisplayIdPattern, sDockedStackMinimizedPattern};
+    private static final String STARTING_WINDOW_PREFIX = "Starting ";
+    private static final String DEBUGGER_WINDOW_PREFIX = "Waiting For Debugger: ";
 
     // Windows in z-order with the top most at the front of the list.
     private List<WindowState> mWindowStates = new ArrayList();
@@ -127,20 +88,20 @@
     private String mAppTransitionState = null;
     private String mInputMethodWindowAppToken = null;
     private Rectangle mStableBounds = new Rectangle();
-    private final Rectangle mDefaultPinnedStackBounds = new Rectangle();
-    private final Rectangle mPinnedStackMovementBounds = new Rectangle();
+    private Rectangle mDefaultPinnedStackBounds = new Rectangle();
+    private Rectangle mPinnedStackMovementBounds = new Rectangle();
     private final LinkedList<String> mSysDump = new LinkedList();
     private int mRotation;
     private int mLastOrientation;
     private boolean mDisplayFrozen;
     private boolean mIsDockedStackMinimized;
 
-    void computeState(ITestDevice device) throws DeviceNotAvailableException {
+    void computeState(ITestDevice device) throws Exception {
         // It is possible the system is in the middle of transition to the right state when we get
         // the dump. We try a few times to get the information we need before giving up.
         int retriesLeft = 3;
         boolean retry = false;
-        String dump = null;
+        byte[] dump = null;
 
         log("==============================");
         log("      WindowManagerState      ");
@@ -157,18 +118,18 @@
                 }
             }
 
-            final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+            final CollectingByteOutputReceiver outputReceiver = new CollectingByteOutputReceiver();
             device.executeShellCommand(DUMPSYS_WINDOW, outputReceiver);
             dump = outputReceiver.getOutput();
-            parseSysDump(dump);
+            try {
+                parseSysDumpProto(dump);
+            } catch (InvalidProtocolBufferException ex) {
+                System.out.println(new String(dump, StandardCharsets.UTF_8));
+            }
 
             retry = mWindowStates.isEmpty() || mFocusedApp == null;
         } while (retry && retriesLeft-- > 0);
 
-        if (retry) {
-            log(dump);
-        }
-
         if (mWindowStates.isEmpty()) {
             logE("No Windows found...");
         }
@@ -180,181 +141,54 @@
         }
     }
 
-    private void parseSysDump(String sysDump) {
+    private void parseSysDumpProto(byte[] sysDump) throws Exception {
         reset();
-
-        Collections.addAll(mSysDump, sysDump.split("\\n"));
-
-        int currentDisplayId = DEFAULT_DISPLAY_ID;
-        while (!mSysDump.isEmpty()) {
-            final Display display =
-                    Display.create(mSysDump, sExtractStackExitPatterns);
-            if (display != null) {
-                log(display.toString());
-                mDisplays.add(display);
-                currentDisplayId = display.mDisplayId;
-                mDisplayStacks.put(currentDisplayId, new ArrayList<>());
-                continue;
-            }
-
-            final WindowStack stack =
-                    WindowStack.create(mSysDump, sStackIdPattern, sExtractStackExitPatterns);
-
-            if (stack != null) {
+        List<WindowState> allWindows = new ArrayList<>();
+        Map<String, WindowState> windowMap = new HashMap<>();
+        WindowManagerServiceProto state = WindowManagerServiceProto.parser().parseFrom(sysDump);
+        if (state.hasFocusedWindow()) {
+            mFocusedWindow = state.getFocusedWindow().getTitle();
+        }
+        mFocusedApp = state.getFocusedApp();
+        for (int i = 0; i < state.getDisplaysCount(); i++) {
+            DisplayProto displayProto = state.getDisplays(i);
+            final Display display = new Display(displayProto);
+            mDisplays.add(display);
+            allWindows.addAll(display.getWindows());
+            List<WindowStack> stacks = new ArrayList<>();
+            for (int j = 0; j < displayProto.getStacksCount(); j++) {
+                StackProto stackProto = displayProto.getStacks(j);
+                final WindowStack stack = new WindowStack(stackProto);
                 mStacks.add(stack);
-                mDisplayStacks.get(currentDisplayId).add(stack);
-                continue;
+                stacks.add(stack);
+                allWindows.addAll(stack.getWindows());
             }
+            mDisplayStacks.put(display.mDisplayId, stacks);
 
-
-            final WindowState ws = WindowState.create(mSysDump, sExtractStackExitPatterns);
-            if (ws != null) {
-                log(ws.toString());
-
-                // Check to see if we are in the middle of transitioning. If we are, we want to
-                // skip dumping until window manager is done transitioning windows.
-                if (ws.isStartingWindow()) {
-                    log("Skipping dump due to starting window transition...");
-                    return;
-                }
-
-                if (ws.isExitingWindow()) {
-                    log("Skipping dump due to exiting window transition...");
-                    return;
-                }
-
-                mWindowStates.add(ws);
-                continue;
-            }
-
-            final String line = mSysDump.pop().trim();
-
-            Matcher matcher = sFocusedWindowPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedWindow = matcher.group(3);
-                log(focusedWindow);
-                mFocusedWindow = focusedWindow;
-                continue;
-            }
-
-            matcher = sAppErrorFocusedWindowPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedWindow = matcher.group(3);
-                log(focusedWindow);
-                mFocusedWindow = focusedWindow;
-                continue;
-            }
-
-            matcher = sWaitingForDebuggerFocusedWindowPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedWindow = matcher.group(3);
-                log(focusedWindow);
-                mFocusedWindow = focusedWindow;
-                continue;
-            }
-
-            matcher = sFocusedAppPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedApp = matcher.group(5);
-                log(focusedApp);
-                mFocusedApp = focusedApp;
-                continue;
-            }
-
-            matcher = sAppTransitionStatePattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String appTransitionState = matcher.group(1);
-                log(appTransitionState);
-                mAppTransitionState = appTransitionState;
-                continue;
-            }
-
-            matcher = sLastAppTransitionPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String lastAppTransitionPattern = matcher.group(1);
-                log(lastAppTransitionPattern);
-                mLastTransition = lastAppTransitionPattern;
-                continue;
-            }
-
-            matcher = sStableBoundsPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                int left = Integer.parseInt(matcher.group(1));
-                int top = Integer.parseInt(matcher.group(2));
-                int right = Integer.parseInt(matcher.group(3));
-                int bottom = Integer.parseInt(matcher.group(4));
-                mStableBounds.setBounds(left, top, right - left, bottom - top);
-                log(mStableBounds.toString());
-                continue;
-            }
-
-            matcher = sDefaultPinnedStackBoundsPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                int left = Integer.parseInt(matcher.group(1));
-                int top = Integer.parseInt(matcher.group(2));
-                int right = Integer.parseInt(matcher.group(3));
-                int bottom = Integer.parseInt(matcher.group(4));
-                mDefaultPinnedStackBounds.setBounds(left, top, right - left, bottom - top);
-                log(mDefaultPinnedStackBounds.toString());
-                continue;
-            }
-
-            matcher = sPinnedStackMovementBoundsPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                int left = Integer.parseInt(matcher.group(1));
-                int top = Integer.parseInt(matcher.group(2));
-                int right = Integer.parseInt(matcher.group(3));
-                int bottom = Integer.parseInt(matcher.group(4));
-                mPinnedStackMovementBounds.setBounds(left, top, right - left, bottom - top);
-                log(mPinnedStackMovementBounds.toString());
-                continue;
-            }
-
-            matcher = sInputMethodWindowPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                mInputMethodWindowAppToken = matcher.group(1);
-                log(mInputMethodWindowAppToken);
-                continue;
-            }
-
-            matcher = sRotationPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                mRotation = Integer.parseInt(matcher.group(1));
-                continue;
-            }
-
-            matcher = sLastOrientationPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                mLastOrientation = Integer.parseInt(matcher.group(1));
-                continue;
-            }
-
-            matcher = sDisplayFrozenPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                mDisplayFrozen = Boolean.parseBoolean(matcher.group(1));
-                continue;
-            }
-
-            matcher = sDockedStackMinimizedPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                mIsDockedStackMinimized = Boolean.parseBoolean(matcher.group(1));
-                continue;
+            // use properties from the default display only
+            if (display.getDisplayId() == DEFAULT_DISPLAY_ID) {
+                mIsDockedStackMinimized = displayProto.getDockedStackDividerController().getMinimizedDock();
+                PinnedStackControllerProto pinnedStackProto = displayProto.getPinnedStackController();
+                mDefaultPinnedStackBounds = WindowContainer.extractBounds(pinnedStackProto.getDefaultBounds());
+                mPinnedStackMovementBounds = WindowContainer.extractBounds(pinnedStackProto.getMovementBounds());
             }
         }
+        for (WindowState w : allWindows) {
+            windowMap.put(w.getToken(), w);
+        }
+        for (int i = 0; i < state.getWindowsCount(); i++) {
+            IdentifierProto identifierProto = state.getWindows(i);
+            String hash_code = Integer.toHexString(identifierProto.getHashCode());
+            mWindowStates.add(windowMap.get(hash_code));
+        }
+        mStableBounds = WindowContainer.extractBounds(state.getPolicy().getStableBounds());
+        mInputMethodWindowAppToken = Integer.toHexString(state.getInputMethodWindow().getHashCode());
+        mDisplayFrozen = state.getDisplayFrozen();
+        mRotation = state.getRotation();
+        mLastOrientation = state.getLastOrientation();
+        AppTransitionProto appTransitionProto = state.getAppTransition();
+        mAppTransitionState = appTransitionProto.getAppTransitionState().name();
+        mLastTransition = appTransitionProto.getLastUsedAppTransition().name();
     }
 
     void getMatchingWindowTokens(final String windowName, List<String> tokenList) {
@@ -582,80 +416,23 @@
 
     static class WindowStack extends WindowContainer {
 
-        private static final Pattern sTaskIdPattern = Pattern.compile("taskId=(\\d+)");
-        private static final Pattern sWindowAnimationBackgroundSurfacePattern =
-                Pattern.compile("mWindowAnimationBackgroundSurface:");
-
         int mStackId;
         ArrayList<WindowTask> mTasks = new ArrayList();
         boolean mWindowAnimationBackgroundSurfaceShowing;
 
-        private WindowStack() {
-
-        }
-
-        static WindowStack create(
-                LinkedList<String> dump, Pattern stackIdPattern, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            final Matcher matcher = stackIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                // Not a stack.
-                return null;
+        WindowStack(StackProto proto) {
+            mStackId = proto.getId();
+            mFullscreen = proto.getFillsParent();
+            if (proto.hasBounds()) {
+                mBounds = extractBounds(proto.getBounds());
             }
-            // For the stack Id line we just read.
-            dump.pop();
-
-            final WindowStack stack = new WindowStack();
-            log(line);
-            final String stackId = matcher.group(1);
-            log(stackId);
-            stack.mStackId = Integer.parseInt(stackId);
-            stack.extract(dump, exitPatterns);
-            return stack;
-        }
-
-        void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-
-            final List<Pattern> taskExitPatterns = new ArrayList();
-            Collections.addAll(taskExitPatterns, exitPatterns);
-            taskExitPatterns.add(sTaskIdPattern);
-            taskExitPatterns.add(sWindowAnimationBackgroundSurfacePattern);
-            final Pattern[] taskExitPatternsArray =
-                    taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]);
-
-            while (!doneExtracting(dump, exitPatterns)) {
-                final WindowTask task =
-                        WindowTask.create(dump, sTaskIdPattern, taskExitPatternsArray);
-
-                if (task != null) {
-                    mTasks.add(task);
-                    continue;
-                }
-
-                final String line = dump.pop().trim();
-
-                if (extractFullscreen(line)) {
-                    continue;
-                }
-
-                if (extractBounds(line)) {
-                    continue;
-                }
-
-                if (extractWindowAnimationBackgroundSurface(line)) {
-                    continue;
-                }
+            for (int i = 0; i < proto.getTasksCount(); i++) {
+                TaskProto taskProto = proto.getTasks(i);
+                WindowTask task = new WindowTask(taskProto);
+                mTasks.add(task);
+                mSubWindows.addAll(task.getWindows());
             }
-        }
-
-        boolean extractWindowAnimationBackgroundSurface(String line) {
-            if (sWindowAnimationBackgroundSurfacePattern.matcher(line).matches()) {
-                log(line);
-                mWindowAnimationBackgroundSurfaceShowing = true;
-                return true;
-            }
-            return false;
+            mWindowAnimationBackgroundSurfaceShowing = proto.getAnimationBackgroundSurfaceIsDimming();
         }
 
         WindowTask getTask(int taskId) {
@@ -673,140 +450,47 @@
     }
 
     static class WindowTask extends WindowContainer {
-        private static final Pattern sTempInsetBoundsPattern =
-                Pattern.compile("mTempInsetBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
-
-        private static final Pattern sAppTokenPattern = Pattern.compile(
-                "Activity #(\\d+) AppWindowToken\\{(\\S+) token=Token\\{(\\S+) "
-                + "ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}\\}\\}");
-
 
         int mTaskId;
         Rectangle mTempInsetBounds;
         List<String> mAppTokens = new ArrayList();
 
-        private WindowTask() {
-        }
-
-        static WindowTask create(
-                LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            final Matcher matcher = taskIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                // Not a task.
-                return null;
+        WindowTask(TaskProto proto) {
+            mTaskId = proto.getId();
+            mFullscreen = proto.getFillsParent();
+            if (proto.hasBounds()) {
+                mBounds = extractBounds(proto.getBounds());
             }
-            // For the task Id line we just read.
-            dump.pop();
-
-            final WindowTask task = new WindowTask();
-            log(line);
-            final String taskId = matcher.group(1);
-            log(taskId);
-            task.mTaskId = Integer.parseInt(taskId);
-            task.extract(dump, exitPatterns);
-            return task;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-            while (!doneExtracting(dump, exitPatterns)) {
-                final String line = dump.pop().trim();
-
-                if (extractFullscreen(line)) {
-                    continue;
-                }
-
-                if (extractBounds(line)) {
-                    continue;
-                }
-
-                Matcher matcher = sTempInsetBoundsPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    mTempInsetBounds = extractBounds(matcher);
-                }
-
-                matcher = sAppTokenPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    final String appToken = matcher.group(6);
-                    log(appToken);
-                    mAppTokens.add(appToken);
-                    continue;
+            for (int i = 0; i < proto.getAppWindowTokensCount(); i++) {
+                AppWindowTokenProto appWindowTokenProto = proto.getAppWindowTokens(i);
+                mAppTokens.add(appWindowTokenProto.getName());
+                WindowTokenProto windowTokenProto = appWindowTokenProto.getWindowToken();
+                for (int j = 0; j < windowTokenProto.getWindowsCount(); j++) {
+                    WindowStateProto windowProto = windowTokenProto.getWindows(j);
+                    WindowState window = new WindowState(windowProto);
+                    mSubWindows.add(window);
+                    mSubWindows.addAll(window.getWindows());
                 }
             }
+            mTempInsetBounds = extractBounds(proto.getTempInsetBounds());
         }
     }
 
     static abstract class WindowContainer {
-        protected static final Pattern sFullscreenPattern = Pattern.compile("mFillsParent=(\\S+)");
-        protected static final Pattern sBoundsPattern =
-                Pattern.compile("mBounds=\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]");
 
         protected boolean mFullscreen;
         protected Rectangle mBounds;
+        protected List<WindowState> mSubWindows = new ArrayList<>();
 
-        static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) {
-            if (dump.isEmpty()) {
-                return true;
-            }
-            final String line = dump.peek().trim();
-
-            for (Pattern pattern : exitPatterns) {
-                if (pattern.matcher(line).matches()) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        boolean extractFullscreen(String line) {
-            final Matcher matcher = sFullscreenPattern.matcher(line);
-            if (!matcher.matches()) {
-                return false;
-            }
-            log(line);
-            final String fullscreen = matcher.group(1);
-            log(fullscreen);
-            mFullscreen = Boolean.valueOf(fullscreen);
-            return true;
-        }
-
-        boolean extractBounds(String line) {
-            final Matcher matcher = sBoundsPattern.matcher(line);
-            if (!matcher.matches()) {
-                return false;
-            }
-            log(line);
-            mBounds = extractBounds(matcher);
-            return true;
-        }
-
-        static Rectangle extractBounds(Matcher matcher) {
-            final int left = Integer.valueOf(matcher.group(1));
-            final int top = Integer.valueOf(matcher.group(2));
-            final int right = Integer.valueOf(matcher.group(3));
-            final int bottom = Integer.valueOf(matcher.group(4));
+        static Rectangle extractBounds(RectProto rectProto) {
+            final int left = rectProto.getLeft();
+            final int top = rectProto.getTop();
+            final int right = rectProto.getRight();
+            final int bottom = rectProto.getBottom();
             final Rectangle rect = new Rectangle(left, top, right - left, bottom - top);
-
-            log(rect.toString());
             return rect;
         }
 
-        static void extractMultipleBounds(Matcher matcher, int groupIndex, Rectangle... rectList) {
-            for (Rectangle rect : rectList) {
-                if (rect == null) {
-                    return;
-                }
-                final int left = Integer.valueOf(matcher.group(groupIndex++));
-                final int top = Integer.valueOf(matcher.group(groupIndex++));
-                final int right = Integer.valueOf(matcher.group(groupIndex++));
-                final int bottom = Integer.valueOf(matcher.group(groupIndex++));
-                rect.setBounds(left, top, right - left, bottom - top);
-            }
-        }
-
         Rectangle getBounds() {
             return mBounds;
         }
@@ -814,21 +498,43 @@
         boolean isFullscreen() {
             return mFullscreen;
         }
+
+        List<WindowState> getWindows() {
+            return mSubWindows;
+        }
     }
 
     static class Display extends WindowContainer {
-        private static final String TAG = "[Display] ";
-
-        private static final Pattern sDisplayInfoPattern =
-                Pattern.compile("(.+) (\\d+)dpi cur=(\\d+)x(\\d+) app=(\\d+)x(\\d+) (.+)");
 
         private final int mDisplayId;
         private Rectangle mDisplayRect = new Rectangle();
         private Rectangle mAppRect = new Rectangle();
         private int mDpi;
 
-        private Display(int displayId) {
-            mDisplayId = displayId;
+        public Display(DisplayProto proto) {
+            mDisplayId = proto.getId();
+            for (int i = 0; i < proto.getAboveAppWindowsCount(); i++) {
+                addWindowsFromTokenProto(proto.getAboveAppWindows(i));
+            }
+            for (int i = 0; i < proto.getBelowAppWindowsCount(); i++) {
+                addWindowsFromTokenProto(proto.getBelowAppWindows(i));
+            }
+            for (int i = 0; i < proto.getImeWindowsCount(); i++) {
+                addWindowsFromTokenProto(proto.getImeWindows(i));
+            }
+            mDpi = proto.getDpi();
+            DisplayInfoProto infoProto = proto.getDisplayInfo();
+            mDisplayRect.setBounds(0, 0, infoProto.getLogicalWidth(), infoProto.getLogicalHeight());
+            mAppRect.setBounds(0, 0, infoProto.getAppWidth(), infoProto.getAppHeight());
+        }
+
+        private void addWindowsFromTokenProto(WindowTokenProto proto) {
+            for (int j = 0; j < proto.getWindowsCount(); j++) {
+                WindowStateProto windowProto = proto.getWindows(j);
+                WindowState childWindow = new WindowState(windowProto);
+                mSubWindows.add(childWindow);
+                mSubWindows.addAll(childWindow.getWindows());
+            }
         }
 
         int getDisplayId() {
@@ -847,48 +553,6 @@
             return mAppRect;
         }
 
-        static Display create(LinkedList<String> dump, Pattern[] exitPatterns) {
-            // TODO: exit pattern for displays?
-            final String line = dump.peek().trim();
-
-            Matcher matcher = sDisplayIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                return null;
-            }
-
-            log(TAG + "DISPLAY_ID: " + line);
-            dump.pop();
-
-            final int displayId = Integer.valueOf(matcher.group(1));
-            final Display display = new Display(displayId);
-            display.extract(dump, exitPatterns);
-            return display;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-            while (!doneExtracting(dump, exitPatterns)) {
-                final String line = dump.pop().trim();
-
-                final Matcher matcher = sDisplayInfoPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "DISPLAY_INFO: " + line);
-                    mDpi = Integer.valueOf(matcher.group(2));
-
-                    final int displayWidth = Integer.valueOf(matcher.group(3));
-                    final int displayHeight = Integer.valueOf(matcher.group(4));
-                    mDisplayRect.setBounds(0, 0, displayWidth, displayHeight);
-
-                    final int appWidth = Integer.valueOf(matcher.group(5));
-                    final int appHeight = Integer.valueOf(matcher.group(6));
-                    mAppRect.setBounds(0, 0, appWidth, appHeight);
-
-                    // break as we don't need other info for now
-                    break;
-                }
-                // Extract other info here if needed
-            }
-        }
-
         @Override
         public String toString() {
             return "Display #" + mDisplayId + ": mDisplayRect=" + mDisplayRect
@@ -906,31 +570,7 @@
         private static final int WINDOW_TYPE_EXITING  = 2;
         private static final int WINDOW_TYPE_DEBUGGER = 3;
 
-        private static final String RECT_STR = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]";
-        private static final String NEGATIVE_VALUES_ALLOWED_RECT_STR =
-                "\\[([-\\d]+),([-\\d]+)\\]\\[([-\\d]+),([-\\d]+)\\]";
-        private static final Pattern sMainFramePattern = Pattern.compile("mFrame=" + RECT_STR + ".+");
-        private static final Pattern sFramePattern =
-                Pattern.compile("Frames: containing=" + RECT_STR + " parent=" + RECT_STR);
-        private static final Pattern sContentFramePattern =
-            Pattern.compile("content=" + RECT_STR + " .+");
-        private static final Pattern sWindowAssociationPattern =
-                Pattern.compile("mDisplayId=(\\d+) stackId=(\\d+) (.+)");
-        private static final Pattern sSurfaceInsetsPattern =
-            Pattern.compile("Cur insets.+surface=" + RECT_STR + ".+");
-        private static final Pattern sContentInsetsPattern =
-                Pattern.compile("Cur insets.+content=" + NEGATIVE_VALUES_ALLOWED_RECT_STR + ".+");
-        private static final Pattern sGivenContentInsetsPattern =
-                Pattern.compile("mGivenContentInsets=" + RECT_STR + ".+");
-        private static final Pattern sCropPattern =
-            Pattern.compile(".+mLastClipRect=" + RECT_STR + ".*");
-        private static final Pattern sSurfacePattern =
-                Pattern.compile("Surface: shown=(\\S+) layer=(\\d+) alpha=[\\d.]+ rect=\\([\\d.-]+,[\\d.-]+\\) [\\d.]+ x [\\d.]+.*");
-        private static final Pattern sAttrsPattern=
-                Pattern.compile("mAttrs=WM\\.LayoutParams\\{.*ty=(\\d+).*\\}");
-
-
-        private final String mName;
+        private String mName;
         private final String mAppToken;
         private final int mWindowType;
         private int mType;
@@ -947,11 +587,45 @@
         private Rectangle mGivenContentInsets = new Rectangle();
         private Rectangle mCrop = new Rectangle();
 
-
-        private WindowState(Matcher matcher, int windowType) {
-            mName = matcher.group(4);
-            mAppToken = matcher.group(2);
-            mWindowType = windowType;
+        WindowState (WindowStateProto proto) {
+            IdentifierProto identifierProto = proto.getIdentifier();
+            mName = identifierProto.getTitle();
+            mAppToken = Integer.toHexString(identifierProto.getHashCode());
+            mDisplayId = proto.getDisplayId();
+            mStackId = proto.getStackId();
+            mType = proto.getAttributes().getType();
+            WindowStateAnimatorProto animatorProto = proto.getAnimator();
+            if (animatorProto.hasSurface()) {
+                WindowSurfaceControllerProto surfaceProto = animatorProto.getSurface();
+                mShown = surfaceProto.getShown();
+                mLayer = surfaceProto.getLayer();
+            }
+            mGivenContentInsets = extractBounds(proto.getGivenContentInsets());
+            mFrame = extractBounds(proto.getFrame());
+            mContainingFrame = extractBounds(proto.getContainingFrame());
+            mParentFrame = extractBounds(proto.getParentFrame());
+            mContentFrame = extractBounds(proto.getContentFrame());
+            mContentInsets = extractBounds(proto.getContentInsets());
+            mSurfaceInsets = extractBounds(proto.getSurfaceInsets());
+            mCrop = extractBounds(animatorProto.getLastClipRect());
+            if (mName.startsWith(STARTING_WINDOW_PREFIX)) {
+                mWindowType = WINDOW_TYPE_STARTING;
+                // Existing code depends on the prefix being removed
+                mName = mName.substring(STARTING_WINDOW_PREFIX.length());
+            } else if (proto.getAnimatingExit()) {
+                mWindowType = WINDOW_TYPE_EXITING;
+            } else if (mName.startsWith(DEBUGGER_WINDOW_PREFIX)) {
+                mWindowType = WINDOW_TYPE_STARTING;
+                mName = mName.substring(DEBUGGER_WINDOW_PREFIX.length());
+            } else {
+                mWindowType = 0;
+            }
+            for (int i = 0; i < proto.getChildWindowsCount(); i++) {
+                WindowStateProto childProto = proto.getChildWindows(i);
+                WindowState childWindow = new WindowState(childProto);
+                mSubWindows.add(childWindow);
+                mSubWindows.addAll(childWindow.getWindows());
+            }
         }
 
         public String getName() {
@@ -1026,109 +700,6 @@
             return mType;
         }
 
-        static WindowState create(LinkedList<String> dump, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            Matcher matcher = sWindowPattern.matcher(line);
-            if (!matcher.matches()) {
-                return null;
-            }
-
-            log(TAG + "WINDOW: " + line);
-            dump.pop();
-
-            final WindowState window;
-            Matcher specialMatcher;
-            if ((specialMatcher = sStartingWindowPattern.matcher(line)).matches()) {
-                log(TAG + "STARTING: " + line);
-                window = new WindowState(specialMatcher, WINDOW_TYPE_STARTING);
-            } else if ((specialMatcher = sExitingWindowPattern.matcher(line)).matches()) {
-                log(TAG + "EXITING: " + line);
-                window = new WindowState(specialMatcher, WINDOW_TYPE_EXITING);
-            } else if ((specialMatcher = sDebuggerWindowPattern.matcher(line)).matches()) {
-                log(TAG + "DEBUGGER: " + line);
-                window = new WindowState(specialMatcher, WINDOW_TYPE_DEBUGGER);
-            } else {
-                window = new WindowState(matcher, WINDOW_TYPE_NORMAL);
-            }
-
-            window.extract(dump, exitPatterns);
-            return window;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-            while (!doneExtracting(dump, exitPatterns)) {
-                final String line = dump.pop().trim();
-
-                Matcher matcher = sWindowAssociationPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "WINDOW_ASSOCIATION: " + line);
-                    mDisplayId = Integer.valueOf(matcher.group(1));
-                    mStackId = Integer.valueOf(matcher.group(2));
-                    continue;
-                }
-
-                matcher = sMainFramePattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "MAIN WINDOW FRAME: " + line);
-                    mFrame = extractBounds(matcher);
-                    continue;
-                }
-
-                matcher = sFramePattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "FRAME: " + line);
-                    extractMultipleBounds(matcher, 1, mContainingFrame, mParentFrame);
-                    continue;
-                }
-
-                matcher = sContentFramePattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "CONTENT FRAME: " + line);
-                    mContentFrame = extractBounds(matcher);
-                }
-
-                matcher = sSurfaceInsetsPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "INSETS: " + line);
-                    mSurfaceInsets = extractBounds(matcher);
-                }
-
-                matcher = sContentInsetsPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "CONTENT INSETS: " + line);
-                    mContentInsets = extractBounds(matcher);
-                }
-
-                matcher = sCropPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "CROP: " + line);
-                    mCrop = extractBounds(matcher);
-                }
-
-                matcher = sSurfacePattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "SURFACE: " + line);
-                    mShown = Boolean.valueOf(matcher.group(1));
-                    mLayer = Integer.valueOf(matcher.group(2));
-                }
-
-                matcher = sAttrsPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "ATTRS: " + line);
-                    mType = Integer.valueOf(matcher.group(1));
-                }
-
-                matcher = sGivenContentInsetsPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "GIVEN CONTENT INSETS: " + line);
-                    mGivenContentInsets = extractBounds(matcher);
-                }
-
-                // Extract other info here if needed
-            }
-        }
-
         private static String getWindowTypeSuffix(int windowType) {
             switch (windowType) {
             case WINDOW_TYPE_STARTING: return " STARTING";
diff --git a/tests/AlarmManager/Android.mk b/tests/AlarmManager/Android.mk
new file mode 100755
index 0000000..a1676ab
--- /dev/null
+++ b/tests/AlarmManager/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES += $(call all-java-files-under, app/src)
+
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_PACKAGE_NAME := CtsAlarmManagerTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/tests/AlarmManager/AndroidManifest.xml b/tests/AlarmManager/AndroidManifest.xml
new file mode 100644
index 0000000..f557b51
--- /dev/null
+++ b/tests/AlarmManager/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.alarmmanager.cts" >
+
+    <application android:label="Cts Alarm Manager Test">
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:functionalTest="true"
+                     android:targetPackage="android.alarmmanager.cts"
+                     android:label="Alarm Manager Tests"/>
+</manifest>
diff --git a/tests/AlarmManager/AndroidTest.xml b/tests/AlarmManager/AndroidTest.xml
new file mode 100644
index 0000000..a31e6da
--- /dev/null
+++ b/tests/AlarmManager/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<configuration description="Config for CTS Alarm Manager test cases">
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAlarmManagerTestCases.apk" />
+        <option name="test-file-name" value="AlarmTestApp.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.alarmmanager.cts" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+
+</configuration>
diff --git a/tests/AlarmManager/app/Android.mk b/tests/AlarmManager/app/Android.mk
new file mode 100644
index 0000000..b2023e9
--- /dev/null
+++ b/tests/AlarmManager/app/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AlarmTestApp
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/AlarmManager/app/AndroidManifest.xml b/tests/AlarmManager/app/AndroidManifest.xml
new file mode 100644
index 0000000..ceb8fb9
--- /dev/null
+++ b/tests/AlarmManager/app/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.alarmmanager.alarmtestapp.cts">
+
+    <application>
+        <activity android:name=".TestAlarmActivity"
+                  android:exported="true" />
+        <receiver android:name=".TestAlarmReceiver" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmActivity.java b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmActivity.java
new file mode 100644
index 0000000..25efc2c
--- /dev/null
+++ b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.alarmmanager.alarmtestapp.cts;
+
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * This Activity is to be used as part of {@link com.android.server.BackgroundRestrictedAlarmsTest}
+ */
+public class TestAlarmActivity extends Activity {
+    private static final String TAG = TestAlarmActivity.class.getSimpleName();
+    private static final String PACKAGE_NAME = "android.alarmmanager.alarmtestapp.cts";
+
+    public static final String ACTION_SET_ALARM = PACKAGE_NAME + ".action.SET_ALARM";
+    public static final String EXTRA_TRIGGER_TIME = PACKAGE_NAME + ".extra.TRIGGER_TIME";
+    public static final String EXTRA_REPEAT_INTERVAL = PACKAGE_NAME + ".extra.REPEAT_INTERVAL";
+    public static final String EXTRA_TYPE = PACKAGE_NAME + ".extra.TYPE";
+    public static final String ACTION_SET_ALARM_CLOCK = PACKAGE_NAME + ".action.SET_ALARM_CLOCK";
+    public static final String EXTRA_ALARM_CLOCK_INFO = PACKAGE_NAME + ".extra.ALARM_CLOCK_INFO";
+    public static final String ACTION_CANCEL_ALL_ALARMS = PACKAGE_NAME + ".action.CANCEL_ALARMS";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final AlarmManager am = getSystemService(AlarmManager.class);
+        final Intent intent = getIntent();
+        final Intent receiverIntent = new Intent(this, TestAlarmReceiver.class);
+        final PendingIntent alarmClockSender =
+                PendingIntent.getBroadcast(this, 0, receiverIntent, 0);
+        final PendingIntent alarmSender = PendingIntent.getBroadcast(this, 1, receiverIntent, 0);
+        switch (intent.getAction()) {
+            case ACTION_SET_ALARM_CLOCK:
+                if (!intent.hasExtra(EXTRA_ALARM_CLOCK_INFO)) {
+                    Log.e(TAG, "No alarm clock supplied");
+                    break;
+                }
+                final AlarmManager.AlarmClockInfo alarmClockInfo =
+                        intent.getParcelableExtra(EXTRA_ALARM_CLOCK_INFO);
+                Log.d(TAG, "Setting alarm clock " + alarmClockInfo);
+                am.setAlarmClock(alarmClockInfo, alarmClockSender);
+                break;
+            case ACTION_SET_ALARM:
+                if (!intent.hasExtra(EXTRA_TYPE) || !intent.hasExtra(EXTRA_TRIGGER_TIME)) {
+                    Log.e(TAG, "Alarm type or trigger time not supplied");
+                    break;
+                }
+                final int type = intent.getIntExtra(EXTRA_TYPE, 0);
+                final long triggerTime = intent.getLongExtra(EXTRA_TRIGGER_TIME, 0);
+                final long interval = intent.getLongExtra(EXTRA_REPEAT_INTERVAL, 0);
+                Log.d(TAG, "Setting alarm: type=" + type + ", triggerTime=" + triggerTime
+                        + ", interval=" + interval);
+                if (interval > 0) {
+                    am.setRepeating(type, triggerTime, interval, alarmSender);
+                } else {
+                    am.setExact(type, triggerTime, alarmSender);
+                }
+                break;
+            case ACTION_CANCEL_ALL_ALARMS:
+                Log.d(TAG, "Cancelling all alarms");
+                am.cancel(alarmClockSender);
+                am.cancel(alarmSender);
+                break;
+            default:
+                Log.e(TAG, "Unspecified action " + intent.getAction());
+                break;
+        }
+        finish();
+    }
+}
\ No newline at end of file
diff --git a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java
new file mode 100644
index 0000000..a083e08
--- /dev/null
+++ b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.alarmmanager.alarmtestapp.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class TestAlarmReceiver extends BroadcastReceiver{
+    private static final String TAG = TestAlarmReceiver.class.getSimpleName();
+    private static final String PACKAGE_NAME = "android.alarmmanager.alarmtestapp.cts";
+    public static final String ACTION_REPORT_ALARM_EXPIRED = PACKAGE_NAME + ".action.ALARM_EXPIRED";
+    public static final String EXTRA_ALARM_COUNT = PACKAGE_NAME + ".extra.ALARM_COUNT";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final int count = intent.getIntExtra(Intent.EXTRA_ALARM_COUNT, 1);
+        Log.d(TAG, "Alarm expired " + count + " times");
+        final Intent reportAlarmIntent = new Intent(ACTION_REPORT_ALARM_EXPIRED);
+        reportAlarmIntent.putExtra(EXTRA_ALARM_COUNT, count);
+        reportAlarmIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        context.sendBroadcast(reportAlarmIntent);
+    }
+}
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java
new file mode 100644
index 0000000..0d6445e
--- /dev/null
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.alarmmanager.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.alarmmanager.alarmtestapp.cts.TestAlarmActivity;
+import android.alarmmanager.alarmtestapp.cts.TestAlarmReceiver;
+import android.app.AlarmManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class BackgroundRestrictedAlarmsTest {
+    private static final String TAG = BackgroundRestrictedAlarmsTest.class.getSimpleName();
+    private static final String TEST_APP_PACKAGE = "android.alarmmanager.alarmtestapp.cts";
+    private static final String TEST_APP_ACTIVITY = TEST_APP_PACKAGE + ".TestAlarmActivity";
+    private static final String APP_OP_RUN_ANY_IN_BACKGROUND = "RUN_ANY_IN_BACKGROUND";
+    private static final String APP_OP_MODE_ALLOWED = "allow";
+    private static final String APP_OP_MODE_IGNORED = "ignore";
+
+    private static final long DEFAULT_WAIT = 1_000;
+    private static final long POLL_INTERVAL = 1_000;
+    private static final long MIN_REPEATING_INTERVAL = 10_000;
+
+    private Object mLock = new Object();
+    private Context mContext;
+    private ComponentName mAlarmActivity;
+    private UiDevice mUiDevice;
+    private int mAlarmCount;
+
+    private final BroadcastReceiver mAlarmStateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.d(TAG, "Received action " + intent.getAction()
+                    + " elapsed: " + SystemClock.elapsedRealtime());
+            synchronized (mLock) {
+                mAlarmCount = intent.getIntExtra(TestAlarmReceiver.EXTRA_ALARM_COUNT, 1);
+            }
+        }
+    };
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mAlarmActivity = new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY);
+        mAlarmCount = 0;
+        updateAlarmManagerConstants();
+        setAppOpsMode(APP_OP_MODE_IGNORED);
+        final IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(TestAlarmReceiver.ACTION_REPORT_ALARM_EXPIRED);
+        mContext.registerReceiver(mAlarmStateReceiver, intentFilter);
+    }
+
+    private void scheduleAlarm(int type, long triggerMillis, long interval) {
+        final Intent setAlarmIntent = new Intent(TestAlarmActivity.ACTION_SET_ALARM);
+        setAlarmIntent.setComponent(mAlarmActivity);
+        setAlarmIntent.putExtra(TestAlarmActivity.EXTRA_TYPE, type);
+        setAlarmIntent.putExtra(TestAlarmActivity.EXTRA_TRIGGER_TIME, triggerMillis);
+        setAlarmIntent.putExtra(TestAlarmActivity.EXTRA_REPEAT_INTERVAL, interval);
+        setAlarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(setAlarmIntent);
+    }
+
+    private void scheduleAlarmClock(long triggerRTC) {
+        AlarmManager.AlarmClockInfo alarmInfo = new AlarmManager.AlarmClockInfo(triggerRTC, null);
+
+        final Intent setAlarmClockIntent = new Intent(TestAlarmActivity.ACTION_SET_ALARM_CLOCK);
+        setAlarmClockIntent.setComponent(mAlarmActivity);
+        setAlarmClockIntent.putExtra(TestAlarmActivity.EXTRA_ALARM_CLOCK_INFO, alarmInfo);
+        setAlarmClockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(setAlarmClockIntent);
+    }
+
+    private static int getMinExpectedExpirations(long now, long start, long interval) {
+        if (now - start <= 1000) {
+            return 0;
+        }
+        return 1 + (int)((now - start - 1000)/interval);
+    }
+
+    @Test
+    public void testRepeatingAlarmBlocked() throws Exception {
+        final long interval = MIN_REPEATING_INTERVAL;
+        final long triggerElapsed = SystemClock.elapsedRealtime() + interval;
+        scheduleAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerElapsed, interval);
+        Thread.sleep(DEFAULT_WAIT);
+        makeTestPackageIdle();
+        Thread.sleep(2 * interval);
+        assertFalse("Alarm got triggered even under restrictions", waitForAlarms(1, DEFAULT_WAIT));
+        Thread.sleep(interval);
+        setAppOpsMode(APP_OP_MODE_ALLOWED);
+        // The alarm is due to go off about 3 times by now. Adding some tolerance just in case
+        // an expiration is due right about now.
+        final int minCount = getMinExpectedExpirations(SystemClock.elapsedRealtime(),
+                triggerElapsed, interval);
+        assertTrue("Alarm should have expired at least " + minCount
+                + " times when restrictions were lifted", waitForAlarms(minCount, DEFAULT_WAIT));
+    }
+
+    @Test
+    public void testAlarmClockNotBlocked() throws Exception {
+        final long nowRTC = System.currentTimeMillis();
+        final long waitInterval = 10_000;
+        final long triggerRTC = nowRTC + waitInterval;
+        scheduleAlarmClock(triggerRTC);
+        Thread.sleep(waitInterval);
+        assertTrue("AlarmClock did not go off as scheduled when under restrictions",
+                waitForAlarms(1, DEFAULT_WAIT));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        deleteAlarmManagerConstants();
+        setAppOpsMode(APP_OP_MODE_ALLOWED);
+        // Cancel any leftover alarms
+        final Intent cancelAlarmsIntent = new Intent(TestAlarmActivity.ACTION_CANCEL_ALL_ALARMS);
+        cancelAlarmsIntent.setComponent(mAlarmActivity);
+        cancelAlarmsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(cancelAlarmsIntent);
+        mContext.unregisterReceiver(mAlarmStateReceiver);
+        // Broadcast unregister may race with the next register in setUp
+        Thread.sleep(DEFAULT_WAIT);
+    }
+
+    private void updateAlarmManagerConstants() throws IOException {
+        String cmd = "settings put global alarm_manager_constants min_interval="
+                + MIN_REPEATING_INTERVAL + ",limit_bg_alarms_enabled=true";
+        mUiDevice.executeShellCommand(cmd);
+    }
+
+    private void deleteAlarmManagerConstants() throws IOException {
+        mUiDevice.executeShellCommand("settings delete global alarm_manager_constants");
+    }
+
+    private void setAppOpsMode(String mode) throws IOException {
+        StringBuilder commandBuilder = new StringBuilder("appops set ")
+                .append(TEST_APP_PACKAGE)
+                .append(" ")
+                .append(APP_OP_RUN_ANY_IN_BACKGROUND)
+                .append(" ")
+                .append(mode);
+        mUiDevice.executeShellCommand(commandBuilder.toString());
+    }
+
+    private void makeTestPackageIdle() throws IOException {
+        StringBuilder commandBuilder = new StringBuilder("am make-uid-idle --user current ")
+                .append(TEST_APP_PACKAGE);
+        mUiDevice.executeShellCommand(commandBuilder.toString());
+    }
+
+    private boolean waitForAlarms(int expectedAlarms, long timeout) throws InterruptedException {
+        final long deadLine = SystemClock.uptimeMillis() + timeout;
+        int alarmCount;
+        do {
+            Thread.sleep(POLL_INTERVAL);
+            synchronized (mLock) {
+                alarmCount = mAlarmCount;
+            }
+        } while (alarmCount < expectedAlarms && SystemClock.uptimeMillis() < deadLine);
+        return alarmCount >= expectedAlarms;
+    }
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
index aa9db4f..c4d1dda 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
@@ -32,7 +32,7 @@
 public class AccessibilityEventTest extends TestCase {
 
     /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int NON_STATIC_FIELD_COUNT = 29;
+    private static final int NON_STATIC_FIELD_COUNT = 31;
 
     /**
      * Test that no new fields have been added without updating the
@@ -206,6 +206,8 @@
         sentEvent.setMaxScrollY(1);
         sentEvent.setScrollX(1);
         sentEvent.setScrollY(1);
+        sentEvent.setScrollDeltaX(3);
+        sentEvent.setScrollDeltaY(3);
         sentEvent.setToIndex(1);
         sentEvent.setScrollable(true);
         sentEvent.setAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
@@ -261,6 +263,10 @@
                 receivedEvent.getScrollX());
         assertSame("scrollY has incorect value", expectedEvent.getScrollY(),
                 receivedEvent.getScrollY());
+        assertSame("scrollDeltaX has incorect value", expectedEvent.getScrollDeltaX(),
+                receivedEvent.getScrollDeltaX());
+        assertSame("scrollDeltaY has incorect value", expectedEvent.getScrollDeltaY(),
+                receivedEvent.getScrollDeltaY());
         assertSame("toIndex has incorect value", expectedEvent.getToIndex(),
                 receivedEvent.getToIndex());
         assertSame("scrollable has incorect value", expectedEvent.isScrollable(),
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
index 7862cb4..5bf02c8 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
@@ -35,7 +35,7 @@
 public class AccessibilityRecordTest extends AndroidTestCase {
 
     /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int NON_STATIC_FIELD_COUNT = 22;
+    private static final int NON_STATIC_FIELD_COUNT = 24;
 
     /**
      * Test that no new fields have been added without updating the
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
index b67fc28..8b1154e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
@@ -63,16 +63,22 @@
         if (mSingleVolume) {
             return;
         }
-        int startingVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY);
-        int otherVolume = (startingVolume == 0) ? 1 : startingVolume - 1;
-        InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService(
-                mInstrumentation, InstrumentedAccessibilityService.class);
-
-        service.runOnServiceSync(() ->
-                mAudioManager.setStreamVolume(AudioManager.STREAM_ACCESSIBILITY, otherVolume, 0));
-        assertEquals("Accessibility service should be able to change accessibility volume",
-                otherVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY));
-        service.runOnServiceSync(() -> mAudioManager.setStreamVolume(
-                AudioManager.STREAM_ACCESSIBILITY, startingVolume, 0));
+        final int startingVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY);
+        final int otherVolume = (startingVolume == 0) ? 1 : startingVolume - 1;
+        final InstrumentedAccessibilityService service = InstrumentedAccessibilityService
+                .enableService(mInstrumentation, InstrumentedAccessibilityService.class);
+        try {
+            service.runOnServiceSync(() ->
+                    mAudioManager.setStreamVolume(AudioManager.STREAM_ACCESSIBILITY, otherVolume,
+                            0));
+            assertEquals("Accessibility service should be able to change accessibility volume",
+                    otherVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY));
+            service.runOnServiceSync(() -> mAudioManager.setStreamVolume(
+                    AudioManager.STREAM_ACCESSIBILITY, startingVolume, 0));
+        } finally {
+            if (service != null) {
+                service.runOnServiceSync(() -> service.disableSelf());
+            }
+        }
     }
 }
diff --git a/tests/app/src/android/app/cts/NotificationChannelGroupTest.java b/tests/app/src/android/app/cts/NotificationChannelGroupTest.java
index 162815f..7931a1f 100644
--- a/tests/app/src/android/app/cts/NotificationChannelGroupTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelGroupTest.java
@@ -37,10 +37,21 @@
         NotificationChannelGroup group =  new NotificationChannelGroup("1", "one");
         assertEquals("1", group.getId());
         assertEquals("one", group.getName());
+        assertFalse(group.isBlocked());
+        assertNull(group.getDescription());
+        assertEquals(0, group.getChannels().size());
+    }
+
+    public void testIsBlocked() {
+        NotificationChannelGroup group =  new NotificationChannelGroup("1", "one");
+        group.setBlocked(true);
+        assertTrue(group.isBlocked());
     }
 
     public void testWriteToParcel() {
         NotificationChannelGroup group = new NotificationChannelGroup("1", "one");
+        group.setBlocked(true);
+        group.setDescription("bananas!");
         Parcel parcel = Parcel.obtain();
         group.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
@@ -51,8 +62,12 @@
 
     public void testClone() {
         NotificationChannelGroup group =  new NotificationChannelGroup("1", "one");
+        group.setBlocked(true);
+        group.setDescription("bananas");
         NotificationChannelGroup cloned = group.clone();
         assertEquals("1", cloned.getId());
         assertEquals("one", cloned.getName());
+        assertTrue(cloned.isBlocked());
+        assertEquals("bananas", cloned.getDescription());
     }
 }
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index b6077ca..a4480f8 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -80,6 +80,12 @@
             }
             mNotificationManager.deleteNotificationChannel(nc.getId());
         }
+
+        List<NotificationChannelGroup> groups = mNotificationManager.getNotificationChannelGroups();
+        // Delete all groups.
+        for (NotificationChannelGroup ncg : groups) {
+            mNotificationManager.deleteNotificationChannelGroup(ncg.getId());
+        }
     }
 
     public void testCreateChannelGroup() throws Exception {
@@ -151,6 +157,46 @@
                 mNotificationManager.getNotificationChannel(mId).getImportance());
     }
 
+    public void testCreateChannel_addToGroup() throws Exception {
+        String oldGroup = null;
+        String newGroup = "new group";
+        mNotificationManager.createNotificationChannelGroup(
+                new NotificationChannelGroup(newGroup, newGroup));
+
+        NotificationChannel channel =
+                new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setGroup(oldGroup);
+        mNotificationManager.createNotificationChannel(channel);
+
+        channel.setGroup(newGroup);
+        mNotificationManager.createNotificationChannel(channel);
+
+        final NotificationChannel updatedChannel =
+                mNotificationManager.getNotificationChannel(mId);
+        assertEquals("Failed to add non-grouped channel to a group on update ",
+                newGroup, updatedChannel.getGroup());
+    }
+
+    public void testCreateChannel_cannotChangeGroup() throws Exception {
+        String oldGroup = "old group";
+        String newGroup = "new group";
+        mNotificationManager.createNotificationChannelGroup(
+                new NotificationChannelGroup(oldGroup, oldGroup));
+        mNotificationManager.createNotificationChannelGroup(
+                new NotificationChannelGroup(newGroup, newGroup));
+
+        NotificationChannel channel =
+                new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setGroup(oldGroup);
+        mNotificationManager.createNotificationChannel(channel);
+        channel.setGroup(newGroup);
+        mNotificationManager.createNotificationChannel(channel);
+        final NotificationChannel updatedChannel =
+                mNotificationManager.getNotificationChannel(mId);
+        assertEquals("Channels should not be allowed to change groups",
+                oldGroup, updatedChannel.getGroup());
+    }
+
     public void testCreateSameChannelDoesNotUpdate() throws Exception {
         final NotificationChannel channel =
                 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
@@ -328,6 +374,54 @@
         }
     }
 
+    public void testNotify_blockedChannel() throws Exception {
+        mNotificationManager.cancelAll();
+
+        NotificationChannel channel =
+                new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_NONE);
+        mNotificationManager.createNotificationChannel(channel);
+
+        int id = 1;
+        final Notification notification =
+                new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+                        .setSmallIcon(R.drawable.black)
+                        .setWhen(System.currentTimeMillis())
+                        .setContentTitle("notify#" + id)
+                        .setContentText("This is #" + id + "notification  ")
+                        .build();
+        mNotificationManager.notify(id, notification);
+
+        if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
+            fail("found unexpected notification id=" + id);
+        }
+    }
+
+    public void testNotify_blockedChannelGroup() throws Exception {
+        mNotificationManager.cancelAll();
+
+        NotificationChannelGroup group = new NotificationChannelGroup(mId, "group name");
+        group.setBlocked(true);
+        mNotificationManager.createNotificationChannelGroup(group);
+        NotificationChannel channel =
+                new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setGroup(mId);
+        mNotificationManager.createNotificationChannel(channel);
+
+        int id = 1;
+        final Notification notification =
+                new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+                        .setSmallIcon(R.drawable.black)
+                        .setWhen(System.currentTimeMillis())
+                        .setContentTitle("notify#" + id)
+                        .setContentText("This is #" + id + "notification  ")
+                        .build();
+        mNotificationManager.notify(id, notification);
+
+        if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
+            fail("found unexpected notification id=" + id);
+        }
+    }
+
     public void testCancel() throws Exception {
         final int id = 9;
         sendNotification(id, R.drawable.black);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 206f180..273d150 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -2744,6 +2744,8 @@
             FillEventHistory.Event event = selection.getEvents().get(0);
             assertThat(event.getType()).isEqualTo(TYPE_DATASET_AUTHENTICATION_SELECTED);
             assertThat(event.getDatasetId()).isEqualTo("name");
+            assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "clientStateValue");
         });
     }
 
@@ -2788,6 +2790,8 @@
             FillEventHistory.Event event = selection.getEvents().get(0);
             assertThat(event.getType()).isEqualTo(TYPE_AUTHENTICATION_SELECTED);
             assertThat(event.getDatasetId()).isNull();
+            assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "clientStateValue");
         });
     }
 
@@ -2796,11 +2800,15 @@
         enableService();
 
         // Set up first partition with an anonymous dataset
+        Bundle clientState1 = new Bundle();
+        clientState1.putCharSequence("clientStateKey", "Value1");
+
         sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
                 new CannedDataset.Builder()
                         .setField(ID_USERNAME, "username")
                         .setPresentation(createPresentation("dataset1"))
                         .build())
+                .setExtras(clientState1)
                 .build());
 
         // Trigger autofill on username
@@ -2812,17 +2820,20 @@
             // Verify fill selection
             FillEventHistory selection = InstrumentedAutoFillService.peekInstance()
                     .getFillEventHistory();
-            assertThat(selection.getClientState()).isNull();
+            assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "Value1");
 
             assertThat(selection.getEvents().size()).isEqualTo(1);
             FillEventHistory.Event event = selection.getEvents().get(0);
             assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
             assertThat(event.getDatasetId()).isNull();
+            assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "Value1");
         });
 
         // Set up second partition with a named dataset
-        Bundle clientState = new Bundle();
-        clientState.putCharSequence("clientStateKey", "clientStateValue");
+        Bundle clientState2 = new Bundle();
+        clientState2.putCharSequence("clientStateKey", "Value2");
 
         sReplier.addResponse(new CannedFillResponse.Builder()
                 .addDataset(
@@ -2837,7 +2848,7 @@
                                 .setPresentation(createPresentation("dataset3"))
                                 .setId("name3")
                                 .build())
-                .setExtras(clientState)
+                .setExtras(clientState2)
                 .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_PASSWORD).build());
 
         // Trigger autofill on password
@@ -2850,12 +2861,14 @@
             FillEventHistory selection = InstrumentedAutoFillService.peekInstance()
                     .getFillEventHistory();
             assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
-                    "clientStateValue");
+                    "Value2");
 
             assertThat(selection.getEvents().size()).isEqualTo(1);
             FillEventHistory.Event event = selection.getEvents().get(0);
             assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
             assertThat(event.getDatasetId()).isEqualTo("name3");
+            assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "Value2");
         });
 
         mActivity.onPassword((v) -> v.setText("new password"));
@@ -2866,16 +2879,20 @@
             FillEventHistory selection = InstrumentedAutoFillService.peekInstance()
                     .getFillEventHistory();
             assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
-                    "clientStateValue");
+                    "Value2");
 
             assertThat(selection.getEvents().size()).isEqualTo(2);
             FillEventHistory.Event event1 = selection.getEvents().get(0);
             assertThat(event1.getType()).isEqualTo(TYPE_DATASET_SELECTED);
             assertThat(event1.getDatasetId()).isEqualTo("name3");
+            assertThat(event1.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "Value2");
 
             FillEventHistory.Event event2 = selection.getEvents().get(1);
             assertThat(event2.getType()).isEqualTo(TYPE_SAVE_SHOWN);
             assertThat(event2.getDatasetId()).isNull();
+            assertThat(event2.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "Value2");
         });
     }
 
@@ -2904,6 +2921,7 @@
             FillEventHistory.Event event = selection.getEvents().get(0);
             assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
             assertThat(event.getDatasetId()).isNull();
+            assertThat(event.getClientState()).isNull();
         });
 
         // Second request
@@ -2946,6 +2964,7 @@
             FillEventHistory.Event event = selection.getEvents().get(0);
             assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
             assertThat(event.getDatasetId()).isNull();
+            assertThat(event.getClientState()).isNull();
         });
 
         // Second request
@@ -2988,6 +3007,7 @@
             FillEventHistory.Event event = selection.getEvents().get(0);
             assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
             assertThat(event.getDatasetId()).isNull();
+            assertThat(event.getClientState()).isNull();
         });
 
         // Second request
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index 333045a..28745f3 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -20,6 +20,7 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java b/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
index b89f9bb..98f1032 100644
--- a/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
+++ b/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
@@ -223,7 +223,7 @@
             if (other instanceof AllocationKey){
                 AllocationKey otherKey = (AllocationKey) other;
 
-                return otherKey.mType.equals(mType) && otherKey.mUsage == otherKey.mUsage;
+                return otherKey.mType.equals(mType) && otherKey.mUsage == mUsage;
             }
 
             return false;
diff --git a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
index 834d37c..0f48364 100644
--- a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
@@ -227,18 +227,15 @@
         verify(spyStateCb, times(1)).onOpened(any(CameraDevice.class));
 
         // Verify that we can no longer open the camera, as it is held by a higher priority process
-        boolean openException = false;
         try {
             manager.openCamera(chosenCamera, spyStateCb, cameraHandler);
+            fail("Didn't receive exception when trying to open camera held by higher priority " +
+                    "process.");
         } catch(CameraAccessException e) {
             assertTrue("Received incorrect camera exception when opening camera: " + e,
                     e.getReason() == CameraAccessException.CAMERA_IN_USE);
-            openException = true;
         }
 
-        assertTrue("Didn't receive exception when trying to open camera held by higher priority " +
-                "process.", openException);
-
         // Verify that attempting to open the camera didn't cause anything weird to happen in the
         // other process.
         List<ErrorLoggingService.LogEvent> eventList2 = null;
diff --git a/tests/core/Android.mk b/tests/core/Android.mk
index 7a2a708..e9c9793 100644
--- a/tests/core/Android.mk
+++ b/tests/core/Android.mk
@@ -14,6 +14,4 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-BUILD_CTSCORE_PACKAGE:=$(LOCAL_PATH)/ctscore.mk
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/core/ctscore.mk b/tests/core/ctscore.mk
deleted file mode 100644
index 10a91f1..0000000
--- a/tests/core/ctscore.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2009 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_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-# don't include these packages in any target
-LOCAL_MODULE_TAGS := optional
-# and when installed explicitly put them in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-# Don't delete META-INF from the core-tests jar
-LOCAL_DONT_DELETE_JAR_META_INF := true
-
-# TODO: Clean up this mess. (b/26483949). libnativehelper_compat_libc++ pulls in its own
-# static copy of libc++ and the libc++ we're bundling here is the platform libc++. This is
-# bround to break but is being submitted as a workaround for failing CTS tests.
-LOCAL_JNI_SHARED_LIBRARIES := libjavacoretests libsqlite_jni libnativehelper_compat_libc++ libc++
-
-# Include both the 32 and 64 bit versions of libjavacoretests,
-# where applicable.
-LOCAL_MULTILIB := both
-
-include $(BUILD_PACKAGE)
diff --git a/tests/core/runner/Android.mk b/tests/core/runner/Android.mk
index 7e4fb0d..f86ee2f 100644
--- a/tests/core/runner/Android.mk
+++ b/tests/core/runner/Android.mk
@@ -14,21 +14,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
-    $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
-include $(CLEAR_VARS)
-
-# include this package in the tests target for continuous testing
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_PACKAGE_NAME := android.core.tests.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
-
-include $(BUILD_CTSCORE_PACKAGE)
-
 #==========================================================
 # Build the core runner.
 #==========================================================
diff --git a/tests/core/runner/src/com/android/cts/core/internal/runner/TestLoader.java b/tests/core/runner/src/com/android/cts/core/internal/runner/TestLoader.java
deleted file mode 100644
index 108e8fd..0000000
--- a/tests/core/runner/src/com/android/cts/core/internal/runner/TestLoader.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * This file is a copy of https://cs.corp.google.com/android/frameworks/testing/runner/src/main/java/android/support/test/internal/runner/TestLoader.java
- * The only changes that have been made starts with // Libcore-specific
- */
-
-package com.android.cts.core.internal.runner;
-
-import android.util.Log;
-
-import org.junit.runner.Description;
-import org.junit.runner.notification.Failure;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class for loading JUnit3 and JUnit4 test classes given a set of potential class names.
- */
-public final class TestLoader {
-
-    private static final String LOG_TAG = "TestLoader";
-    // Libcore-specific change: Fully qualified name of TestNG annotation class.
-    private static final String TESTNG_TEST = "org.testng.annotations.Test";
-
-    private Map<String, Class<?>> mLoadedClassesMap = new LinkedHashMap<String, Class<?>>();
-    private Map<String, Failure> mLoadFailuresMap = new LinkedHashMap<String, Failure>();
-
-    private ClassLoader mClassLoader;
-
-    /**
-     * Set the {@link ClassLoader} to be used to load test cases.
-     *
-     * @param loader {@link ClassLoader} to load test cases with.
-     */
-    public void setClassLoader(ClassLoader loader) {
-        mClassLoader = loader;
-    }
-
-    /**
-     * Loads the test class from a given class name if its not already loaded.
-     * <p/>
-     * Will store the result internally. Successfully loaded classes can be retrieved via
-     * {@link #getLoadedClasses()}, failures via {@link #getLoadFailures()}.
-     *
-     * @param className the class name to attempt to load
-     * @return the loaded class or null.
-     */
-    public Class<?> loadClass(String className) {
-        Class<?> loadedClass = doLoadClass(className);
-        if (loadedClass != null) {
-            mLoadedClassesMap.put(className, loadedClass);
-        }
-        return loadedClass;
-    }
-
-    protected ClassLoader getClassLoader() {
-        if (mClassLoader != null) {
-            return mClassLoader;
-        }
-
-        // TODO: InstrumentationTestRunner uses
-        // Class.forName(className, false, getTargetContext().getClassLoader());
-        // Evaluate if that is needed. Initial testing indicates
-        // getTargetContext().getClassLoader() == this.getClass().getClassLoader()
-        return this.getClass().getClassLoader();
-    }
-
-    private Class<?> doLoadClass(String className) {
-        if (mLoadFailuresMap.containsKey(className)) {
-            // Don't load classes that already failed to load
-            return null;
-        } else if (mLoadedClassesMap.containsKey(className)) {
-            // Class with the same name was already loaded, return it
-            return mLoadedClassesMap.get(className);
-        }
-
-        try {
-            ClassLoader myClassLoader = getClassLoader();
-            return Class.forName(className, false, myClassLoader);
-        } catch (ClassNotFoundException e) {
-            String errMsg = String.format("Could not find class: %s", className);
-            Log.e(LOG_TAG, errMsg);
-            Description description = Description.createSuiteDescription(className);
-            Failure failure = new Failure(description, e);
-            mLoadFailuresMap.put(className, failure);
-        }
-        return null;
-    }
-
-    /**
-     * Loads the test class from the given class name.
-     * <p/>
-     * Similar to {@link #loadClass(String)}, but will ignore classes that are
-     * not tests.
-     *
-     * @param className the class name to attempt to load
-     * @return the loaded class or null.
-     */
-    public Class<?> loadIfTest(String className) {
-        Class<?> loadedClass = doLoadClass(className);
-        if (loadedClass != null && isTestClass(loadedClass)) {
-            mLoadedClassesMap.put(className, loadedClass);
-            return loadedClass;
-        }
-        return null;
-    }
-
-    /**
-     * @return whether this {@link TestLoader} contains any loaded classes or load failures.
-     */
-    public boolean isEmpty() {
-        return mLoadedClassesMap.isEmpty() && mLoadFailuresMap.isEmpty();
-    }
-
-    /**
-     * Get the {@link Collection) of classes successfully loaded via
-     * {@link #loadIfTest(String)} calls.
-     */
-    public Collection<Class<?>> getLoadedClasses() {
-        return mLoadedClassesMap.values();
-    }
-
-    /**
-     * Get the {@link List) of {@link Failure} that occurred during
-     * {@link #loadIfTest(String)} calls.
-     */
-    public Collection<Failure> getLoadFailures() {
-        return mLoadFailuresMap.values();
-    }
-
-    /**
-     * Determines if given class is a valid test class.
-     *
-     * @param loadedClass
-     * @return <code>true</code> if loadedClass is a test
-     */
-    private boolean isTestClass(Class<?> loadedClass) {
-        try {
-            if (Modifier.isAbstract(loadedClass.getModifiers())) {
-                logDebug(String.format("Skipping abstract class %s: not a test",
-                        loadedClass.getName()));
-                return false;
-            }
-            // Libcore-specific change: Also consider TestNG annotated classes.
-            if (isTestNgTestClass(loadedClass)) {
-              return true;
-            }
-            // TODO: try to find upstream junit calls to replace these checks
-            if (junit.framework.Test.class.isAssignableFrom(loadedClass)) {
-                // ensure that if a TestCase, it has at least one test method otherwise
-                // TestSuite will throw error
-                if (junit.framework.TestCase.class.isAssignableFrom(loadedClass)) {
-                    return hasJUnit3TestMethod(loadedClass);
-                }
-                return true;
-            }
-            // TODO: look for a 'suite' method?
-            if (loadedClass.isAnnotationPresent(org.junit.runner.RunWith.class)) {
-                return true;
-            }
-            for (Method testMethod : loadedClass.getMethods()) {
-                if (testMethod.isAnnotationPresent(org.junit.Test.class)) {
-                    return true;
-                }
-            }
-            logDebug(String.format("Skipping class %s: not a test", loadedClass.getName()));
-            return false;
-        } catch (Exception e) {
-            // Defensively catch exceptions - Will throw runtime exception if it cannot load methods.
-            // For earlier versions of Android (Pre-ICS), Dalvik might try to initialize a class
-            // during getMethods(), fail to do so, hide the error and throw a NoSuchMethodException.
-            // Since the java.lang.Class.getMethods does not declare such an exception, resort to a
-            // generic catch all.
-            // For ICS+, Dalvik will throw a NoClassDefFoundException.
-            Log.w(LOG_TAG, String.format("%s in isTestClass for %s", e.toString(),
-                    loadedClass.getName()));
-            return false;
-        } catch (Error e) {
-            // defensively catch Errors too
-            Log.w(LOG_TAG, String.format("%s in isTestClass for %s", e.toString(),
-                    loadedClass.getName()));
-            return false;
-        }
-    }
-
-    private boolean hasJUnit3TestMethod(Class<?> loadedClass) {
-        for (Method testMethod : loadedClass.getMethods()) {
-            if (isPublicTestMethod(testMethod)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // copied from junit.framework.TestSuite
-    private boolean isPublicTestMethod(Method m) {
-        return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
-    }
-
-    // copied from junit.framework.TestSuite
-    private boolean isTestMethod(Method m) {
-        return m.getParameterTypes().length == 0 && m.getName().startsWith("test")
-                && m.getReturnType().equals(Void.TYPE);
-    }
-
-    // Libcore-specific change: Add method for checking TestNG-annotated classes.
-    private static boolean isTestNgTestClass(Class<?> cls) {
-      // TestNG test is either marked @Test at the class
-      for (Annotation a : cls.getAnnotations()) {
-          if (a.annotationType().getName().equals(TESTNG_TEST)) {
-              return true;
-          }
-      }
-
-      // Or It's marked @Test at the method level
-      for (Method m : cls.getDeclaredMethods()) {
-        for (Annotation a : m.getAnnotations()) {
-          if (a.annotationType().getName().equals(TESTNG_TEST)) {
-              return true;
-          }
-        }
-      }
-
-      return false;
-    }
-
-
-    /**
-     * Utility method for logging debug messages. Only actually logs a message if LOG_TAG is marked
-     * as loggable to limit log spam during normal use.
-     */
-    private void logDebug(String msg) {
-        if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
-            Log.d(LOG_TAG, msg);
-        }
-    }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
deleted file mode 100644
index 4b18cdc..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.core.runner;
-
-import android.support.test.runner.AndroidJUnitRunner;
-
-/**
- * Constants used to communicate to and from {@link AndroidJUnitRunner}.
- */
-public interface AndroidJUnitRunnerConstants {
-
-    /**
-     * The name of the file containing the names of the tests to run.
-     *
-     * <p>This is an internal constant used within
-     * {@code android.support.test.internal.runner.RunnerArgs}, which is used on both the server
-     * and
-     * client side. The constant is used when there are too many test names to pass on the command
-     * line, in which case they are stored in a file that is pushed to the device and then the
-     * location of that file is passed in this argument. The {@code RunnerArgs} on the client will
-     * read the contents of that file in order to retrieve the list of names and then return that
-     * to
-     * its client without the client being aware of how that was done.
-     */
-    String ARGUMENT_TEST_FILE = "testFile";
-
-    /**
-     * The name of the file containing the names of the tests not to run.
-     *
-     * <p>This is an internal constant used within
-     * {@code android.support.test.internal.runner.RunnerArgs}, which is used on both the server
-     * and
-     * client side. The constant is used when there are too many test names to pass on the command
-     * line, in which case they are stored in a file that is pushed to the device and then the
-     * location of that file is passed in this argument. The {@code RunnerArgs} on the client will
-     * read the contents of that file in order to retrieve the list of names and then return that
-     * to
-     * its client without the client being aware of how that was done.
-     */
-    String ARGUMENT_NOT_TEST_FILE = "notTestFile";
-
-    /**
-     * A comma separated list of the names of test classes to run.
-     *
-     * <p>The equivalent constant in {@code InstrumentationTestRunner} is hidden and so not
-     * available
-     * through the public API.
-     */
-    String ARGUMENT_TEST_CLASS = "class";
-
-    /**
-     * A comma separated list of the names of test classes not to run
-     */
-    String ARGUMENT_NOT_TEST_CLASS = "notClass";
-
-    /**
-     * A comma separated list of the names of test packages to run.
-     *
-     * <p>The equivalent constant in {@code InstrumentationTestRunner} is hidden and so not
-     * available
-     * through the public API.
-     */
-    String ARGUMENT_TEST_PACKAGE = "package";
-
-    /**
-     * A comma separated list of the names of test packages not to run.
-     */
-    String ARGUMENT_NOT_TEST_PACKAGE = "notPackage";
-
-    /**
-     * Log the results as if the tests were executed but don't actually run the tests.
-     *
-     * <p>The equivalent constant in {@code InstrumentationTestRunner} is private.
-     */
-    String ARGUMENT_LOG_ONLY = "log";
-
-    /**
-     * Wait for the debugger before starting.
-     *
-     * <p>There is no equivalent constant in {@code InstrumentationTestRunner} but the string is
-     * used
-     * within that class.
-     */
-    String ARGUMENT_DEBUG = "debug";
-
-    /**
-     * Only count the number of tests to run.
-     *
-     * <p>There is no equivalent constant in {@code InstrumentationTestRunner} but the string is
-     * used
-     * within that class.
-     */
-    String ARGUMENT_COUNT = "count";
-
-    /**
-     * The per test timeout value.
-     */
-    String ARGUMENT_TIMEOUT = "timeout_msec";
-
-    /**
-     * Token representing how long (in seconds) the current test took to execute.
-     *
-     * <p>The equivalent constant in {@code InstrumentationTestRunner} is private.
-     */
-    String REPORT_KEY_RUNTIME = "runtime";
-
-    /**
-     * An identifier for tests run using this class.
-     */
-    String REPORT_VALUE_ID = "CoreTestRunner";
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
deleted file mode 100644
index 42b6684..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
+++ /dev/null
@@ -1,355 +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.core.runner;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.os.Bundle;
-import android.os.Debug;
-import android.support.test.internal.runner.listener.InstrumentationResultPrinter;
-import android.support.test.internal.runner.listener.InstrumentationRunListener;
-import android.support.test.internal.util.AndroidRunnerParams;
-import android.util.Log;
-import com.android.cts.core.runner.support.ExtendedAndroidRunnerBuilder;
-import com.google.common.base.Splitter;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.junit.runner.Computer;
-import org.junit.runner.JUnitCore;
-import org.junit.runner.Request;
-import org.junit.runner.Result;
-import org.junit.runner.Runner;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runner.manipulation.Filterable;
-import org.junit.runner.manipulation.NoTestsRemainException;
-import org.junit.runner.notification.RunListener;
-import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.RunnerBuilder;
-
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_NOT_TEST_CLASS;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_NOT_TEST_FILE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_NOT_TEST_PACKAGE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_PACKAGE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TIMEOUT;
-
-/**
- * A drop-in replacement for AndroidJUnitTestRunner, which understands the same arguments, and has
- * similar functionality, but can filter by expectations and allows a custom runner-builder to be
- * provided.
- */
-public class CoreTestRunner extends Instrumentation {
-
-    static final String TAG = "LibcoreTestRunner";
-
-    private static final java.lang.String ARGUMENT_ROOT_CLASSES = "core-root-classes";
-
-    private static final String ARGUMENT_CORE_LISTENER = "core-listener";
-
-    private static final Splitter CLASS_LIST_SPLITTER = Splitter.on(',').trimResults();
-
-    /** The args for the runner. */
-    private Bundle args;
-
-    /** Only log the number and names of tests, and not run them. */
-    private boolean logOnly;
-
-    /** The amount of time in millis to wait for a single test to complete. */
-    private long testTimeout;
-
-    /**
-     * The list of tests to run.
-     */
-    private TestList testList;
-
-    /**
-     * The list of {@link RunListener} classes to create.
-     */
-    private List<Class<? extends RunListener>> listenerClasses;
-    private Filter expectationFilter;
-
-    @Override
-    public void onCreate(final Bundle args) {
-        super.onCreate(args);
-        this.args = args;
-
-        boolean debug = "true".equalsIgnoreCase(args.getString(ARGUMENT_DEBUG));
-        if (debug) {
-            Log.i(TAG, "Waiting for debugger to connect...");
-            Debug.waitForDebugger();
-            Log.i(TAG, "Debugger connected.");
-        }
-
-        // Log the message only after getting a value from the args so that the args are
-        // unparceled.
-        Log.d(TAG, "In OnCreate: " + args);
-
-        // Treat logOnly and count as the same. This is not quite true as count should only send
-        // the host the number of tests but logOnly should send the name and number. However,
-        // this is how this has always behaved and it does not appear to have caused any problems.
-        // Changing it seems unnecessary given that count is CTSv1 only and CTSv1 will be removed
-        // soon now that CTSv2 is ready.
-        boolean testCountOnly = args.getBoolean(ARGUMENT_COUNT);
-        this.logOnly = "true".equalsIgnoreCase(args.getString(ARGUMENT_LOG_ONLY)) || testCountOnly;
-        this.testTimeout = parseUnsignedLong(args.getString(ARGUMENT_TIMEOUT), ARGUMENT_TIMEOUT);
-
-        expectationFilter = new ExpectationBasedFilter(args);
-
-        // The test can be run specifying a list of tests to run, or as cts-tradefed does it,
-        // by passing a fileName with a test to run on each line.
-        Set<String> testNameSet = new HashSet<>();
-        String arg;
-        if ((arg = args.getString(ARGUMENT_TEST_FILE)) != null) {
-            // The tests are specified in a file.
-            try {
-                testNameSet.addAll(readTestsFromFile(arg));
-            } catch (IOException err) {
-                finish(Activity.RESULT_CANCELED, new Bundle());
-                return;
-            }
-        } else if ((arg = args.getString(ARGUMENT_TEST_CLASS)) != null) {
-            // The tests are specified in a String passed in the bundle.
-            String[] tests = arg.split(",");
-            testNameSet.addAll(Arrays.asList(tests));
-        }
-
-        // Tests may be excluded from the run by passing a list of tests not to run,
-        // or by passing a fileName with a test not to run on each line.
-        Set<String> notTestNameSet = new HashSet<>();
-        if ((arg = args.getString(ARGUMENT_NOT_TEST_FILE)) != null) {
-            // The tests are specified in a file.
-            try {
-                notTestNameSet.addAll(readTestsFromFile(arg));
-            } catch (IOException err) {
-                finish(Activity.RESULT_CANCELED, new Bundle());
-                return;
-            }
-        } else if ((arg = args.getString(ARGUMENT_NOT_TEST_CLASS)) != null) {
-            // The classes are specified in a String passed in the bundle
-            String[] tests = arg.split(",");
-            notTestNameSet.addAll(Arrays.asList(tests));
-        }
-
-        Set<String> packageNameSet = new HashSet<>();
-        if ((arg = args.getString(ARGUMENT_TEST_PACKAGE)) != null) {
-            // The packages are specified in a String passed in the bundle
-            String[] packages = arg.split(",");
-            packageNameSet.addAll(Arrays.asList(packages));
-        }
-
-        Set<String> notPackageNameSet = new HashSet<>();
-        if ((arg = args.getString(ARGUMENT_NOT_TEST_PACKAGE)) != null) {
-            // The packages are specified in a String passed in the bundle
-            String[] packages = arg.split(",");
-            notPackageNameSet.addAll(Arrays.asList(packages));
-        }
-
-        List<String> roots = getRootClassNames(args);
-        if (roots == null) {
-            // Find all test classes
-            Collection<Class<?>> classes = TestClassFinder.getClasses(
-                Collections.singletonList(getContext().getPackageCodePath()),
-                getClass().getClassLoader());
-            testList = new TestList(classes);
-        } else {
-            testList = TestList.rootList(roots);
-        }
-
-        testList.addIncludeTestPackages(packageNameSet);
-        testList.addExcludeTestPackages(notPackageNameSet);
-        testList.addIncludeTests(testNameSet);
-        testList.addExcludeTests(notTestNameSet);
-
-        listenerClasses = new ArrayList<>();
-        String listenerArg = args.getString(ARGUMENT_CORE_LISTENER);
-        if (listenerArg != null) {
-            List<String> listenerClassNames = CLASS_LIST_SPLITTER.splitToList(listenerArg);
-            for (String listenerClassName : listenerClassNames) {
-                try {
-                    Class<? extends RunListener> listenerClass = Class.forName(listenerClassName)
-                            .asSubclass(RunListener.class);
-                    listenerClasses.add(listenerClass);
-                } catch (ClassNotFoundException e) {
-                    Log.e(TAG, "Could not load listener class: " + listenerClassName, e);
-                }
-            }
-        }
-
-        start();
-    }
-
-    private List<String> getRootClassNames(Bundle args) {
-        String rootClasses = args.getString(ARGUMENT_ROOT_CLASSES);
-        List<String> roots;
-        if (rootClasses == null) {
-            roots = null;
-        } else {
-            roots = CLASS_LIST_SPLITTER.splitToList(rootClasses);
-        }
-        return roots;
-    }
-
-    @Override
-    public void onStart() {
-        if (logOnly) {
-            Log.d(TAG, "Counting/logging tests only");
-        } else {
-            Log.d(TAG, "Running tests");
-        }
-
-        AndroidRunnerParams runnerParams = new AndroidRunnerParams(this, args,
-                false, testTimeout, false /*ignoreSuiteMethods*/);
-
-        Runner runner;
-        try {
-            RunnerBuilder runnerBuilder = new ExtendedAndroidRunnerBuilder(runnerParams);
-            Class[] classes = testList.getClassesToRun();
-            for (Class cls : classes) {
-              Log.d(TAG, "Found class to run: " + cls.getName());
-            }
-            runner = new Computer().getSuite(runnerBuilder, classes);
-
-            if (runner instanceof Filterable) {
-                Log.d(TAG, "Applying filters");
-                Filterable filterable = (Filterable) runner;
-
-                // Filter out all the tests that are expected to fail.
-                try {
-                    filterable.filter(expectationFilter);
-                } catch (NoTestsRemainException e) {
-                    // Sometimes filtering will remove all tests but we do not care about that.
-                }
-                Log.d(TAG, "Applied filters");
-            }
-
-            // If the tests are only supposed to be logged and not actually run then replace the
-            // runner with a runner that will fire notifications for all the tests that would have
-            // been run. This is needed because CTSv2 does a log only run through a CTS module in
-            // order to generate a list of tests that will be run so that it can monitor them.
-            // Encapsulating that in a Runner implementation makes it easier to leverage the
-            // existing code for running tests.
-            if (logOnly) {
-                runner = new DescriptionHierarchyNotifier(runner.getDescription());
-            }
-
-        } catch (InitializationError e) {
-            throw new RuntimeException("Could not create a suite", e);
-        }
-
-        InstrumentationResultPrinter instrumentationResultPrinter =
-                new InstrumentationResultPrinter();
-        instrumentationResultPrinter.setInstrumentation(this);
-
-        JUnitCore core = new JUnitCore();
-        core.addListener(instrumentationResultPrinter);
-
-        // If not logging the list of tests then add any additional configured listeners. These
-        // must be added before firing any events.
-        if (!logOnly) {
-            // Add additional configured listeners.
-            for (Class<? extends RunListener> listenerClass : listenerClasses) {
-                try {
-                    RunListener runListener = listenerClass.newInstance();
-                    if (runListener instanceof InstrumentationRunListener) {
-                        ((InstrumentationRunListener) runListener).setInstrumentation(this);
-                    }
-                    core.addListener(runListener);
-                } catch (InstantiationException | IllegalAccessException e) {
-                    Log.e(TAG,
-                            "Could not create instance of listener: " + listenerClass, e);
-                }
-            }
-        }
-
-        Log.d(TAG, "Finished preparations, running/listing tests");
-
-        Bundle results = new Bundle();
-        Result junitResults = new Result();
-        try {
-            junitResults = core.run(Request.runner(runner));
-        } catch (RuntimeException e) {
-            final String msg = "Fatal exception when running tests";
-            Log.e(TAG, msg, e);
-            // report the exception to instrumentation out
-            results.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
-                    msg + "\n" + Log.getStackTraceString(e));
-        } finally {
-            ByteArrayOutputStream summaryStream = new ByteArrayOutputStream();
-            // create the stream used to output summary data to the user
-            PrintStream summaryWriter = new PrintStream(summaryStream);
-            instrumentationResultPrinter.instrumentationRunFinished(summaryWriter,
-                    results, junitResults);
-            summaryWriter.close();
-            results.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
-                    String.format("\n%s", summaryStream.toString()));
-        }
-
-
-        Log.d(TAG, "Finished");
-        finish(Activity.RESULT_OK, results);
-    }
-
-    /**
-     * Read tests from a specified file.
-     *
-     * @return class names of tests. If there was an error reading the file, null is returned.
-     */
-    private static List<String> readTestsFromFile(String fileName) throws IOException {
-        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
-            List<String> tests = new ArrayList<>();
-            String line;
-            while ((line = br.readLine()) != null) {
-                tests.add(line);
-            }
-            return tests;
-        } catch (IOException err) {
-            Log.e(TAG, "There was an error reading the test class list: " + err.getMessage());
-            throw err;
-        }
-    }
-
-    /**
-     * Parse long from given value - except either Long or String.
-     *
-     * @return the value, -1 if not found
-     * @throws NumberFormatException if value is negative or not a number
-     */
-    private static long parseUnsignedLong(Object value, String name) {
-        if (value != null) {
-            long longValue = Long.parseLong(value.toString());
-            if (longValue < 0) {
-                throw new NumberFormatException(name + " can not be negative");
-            }
-            return longValue;
-        }
-        return -1;
-    }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/DescriptionHierarchyNotifier.java b/tests/core/runner/src/com/android/cts/core/runner/DescriptionHierarchyNotifier.java
deleted file mode 100644
index 5c94fd7..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/DescriptionHierarchyNotifier.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.core.runner;
-
-import java.util.List;
-import org.junit.runner.Description;
-import org.junit.runner.Runner;
-import org.junit.runner.notification.RunNotifier;
-
-/**
- * A {@link Runner} that does not actually run any tests but simply fires events for all leaf
- * {@link Description} instances in the supplied {@link Description} hierarchy.
- */
-class DescriptionHierarchyNotifier extends Runner {
-
-    private final Description description;
-
-    DescriptionHierarchyNotifier(Description description) {
-        this.description = description;
-    }
-
-    @Override
-    public Description getDescription() {
-        return description;
-    }
-
-    @Override
-    public void run(RunNotifier notifier) {
-        generateListOfTests(notifier, description);
-    }
-
-    /**
-     * Generates a list of tests to run by recursing over the {@link Description} hierarchy and
-     * firing events to simulate the tests being run successfully.
-     * @param runNotifier the notifier to which the events are sent.
-     * @param description the description to traverse.
-     */
-    private void generateListOfTests(RunNotifier runNotifier, Description description) {
-        List<Description> children = description.getChildren();
-        if (children.isEmpty()) {
-            runNotifier.fireTestStarted(description);
-            runNotifier.fireTestFinished(description);
-        } else {
-            for (Description child : children) {
-                generateListOfTests(runNotifier, child);
-            }
-        }
-    }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java b/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
index 90034ec..f409dbd 100644
--- a/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
@@ -105,7 +105,7 @@
             if (expectationStore != null) {
                 Expectation expectation = expectationStore.get(testName);
                 if (expectation.getResult() != Result.SUCCESS) {
-                    Log.d(CoreTestRunner.TAG, "Excluding test " + testDescription
+                    Log.d(TAG, "Excluding test " + testDescription
                             + " as it matches expectation: " + expectation);
                     return false;
                 }
diff --git a/tests/core/runner/src/com/android/cts/core/runner/TestClassFinder.java b/tests/core/runner/src/com/android/cts/core/runner/TestClassFinder.java
deleted file mode 100644
index 6ad95f6..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/TestClassFinder.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.core.runner;
-
-import android.support.test.internal.runner.ClassPathScanner;
-import android.support.test.internal.runner.ClassPathScanner.ClassNameFilter;
-import android.util.Log;
-
-import com.android.cts.core.internal.runner.TestLoader;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Set;
-
-import dalvik.system.DexFile;
-
-/**
- * Find tests in the current APK.
- */
-public class TestClassFinder {
-
-    private static final String TAG = "TestClassFinder";
-    private static final boolean DEBUG = false;
-
-    // Excluded test packages
-    private static final String[] DEFAULT_EXCLUDED_PACKAGES = {
-            "junit",
-            "org.junit",
-            "org.hamcrest",
-            "org.mockito",// exclude Mockito for performance and to prevent JVM related errors
-            "android.support.test.internal.runner.junit3",// always skip AndroidTestSuite
-    };
-
-    static Collection<Class<?>> getClasses(List<String> apks, ClassLoader loader) {
-        if (DEBUG) {
-          Log.d(TAG, "getClasses: =======================================");
-
-          for (String apkPath : apks) {
-            Log.d(TAG, "getClasses: -------------------------------");
-            Log.d(TAG, "getClasses: APK " + apkPath);
-
-            DexFile dexFile = null;
-            try {
-                dexFile = new DexFile(apkPath);
-                Enumeration<String> apkClassNames = dexFile.entries();
-                while (apkClassNames.hasMoreElements()) {
-                    String apkClassName = apkClassNames.nextElement();
-                    Log.d(TAG, "getClasses: DexClass element " + apkClassName);
-                }
-            } catch (IOException e) {
-              throw new AssertionError(e);
-            } finally {
-                if (dexFile != null) {
-                  try {
-                    dexFile.close();
-                  } catch (IOException e) {
-                    throw new AssertionError(e);
-                  }
-                }
-            }
-            Log.d(TAG, "getClasses: -------------------------------");
-          }
-        }  // if DEBUG
-
-        List<Class<?>> classes = new ArrayList<>();
-        ClassPathScanner scanner = new ClassPathScanner(apks);
-
-        ClassPathScanner.ChainedClassNameFilter filter =
-                new ClassPathScanner.ChainedClassNameFilter();
-        // exclude inner classes
-        filter.add(new ClassPathScanner.ExternalClassNameFilter());
-
-        // exclude default classes
-        for (String defaultExcludedPackage : DEFAULT_EXCLUDED_PACKAGES) {
-            filter.add(new ExcludePackageNameFilter(defaultExcludedPackage));
-        }
-
-        // exclude any classes that aren't a "test class" (see #loadIfTest)
-        TestLoader testLoader = new TestLoader();
-        testLoader.setClassLoader(loader);
-
-        try {
-            Set<String> classNames = scanner.getClassPathEntries(filter);
-            for (String className : classNames) {
-                // Important: This further acts as an additional filter;
-                // classes that aren't a "test class" are never loaded.
-                Class<?> cls = testLoader.loadIfTest(className);
-                if (cls != null) {
-                    classes.add(cls);
-
-                    if (DEBUG) {
-                      Log.d(TAG, "getClasses: Loaded " + className);
-                    }
-                } else if (DEBUG) {
-                  Log.d(TAG, "getClasses: Failed to load class " + className);
-                }
-            }
-            return classes;
-        } catch (IOException e) {
-            Log.e(CoreTestRunner.TAG, "Failed to scan classes", e);
-        }
-
-
-        if (DEBUG) {
-            Log.d(TAG, "getClasses: =======================================");
-        }
-
-        return testLoader.getLoadedClasses();
-    }
-
-    /**
-     * A {@link ClassNameFilter} that only rejects a given package names within the given namespace.
-     */
-    public static class ExcludePackageNameFilter implements ClassNameFilter {
-
-        private final String mPkgName;
-
-        ExcludePackageNameFilter(String pkgName) {
-            if (!pkgName.endsWith(".")) {
-                mPkgName = String.format("%s.", pkgName);
-            } else {
-                mPkgName = pkgName;
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean accept(String pathName) {
-            return !pathName.startsWith(mPkgName);
-        }
-    }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/TestList.java b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
deleted file mode 100644
index 9d97501..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/TestList.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.core.runner;
-
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.Nullable;
-
-/**
- * A list of the tests to run.
- */
-class TestList {
-
-    /** The set of test pacakges to run */
-    private final Set<String> mIncludedPackages = new HashSet<>();
-
-    /** The set of test packages not to run */
-    private final Set<String> mExcludedPackages = new HashSet<>();
-
-    /** The set of tests (classes or methods) to run */
-    private final Set<String> mIncludedTests = new HashSet<>();
-
-    /** The set of tests (classes or methods) not to run */
-    private final Set<String> mExcludedTests = new HashSet<>();
-
-    /** The list of all test classes to run (without filtering applied)*/
-    private final Collection<Class<?>> classesToRun;
-
-    public static TestList rootList(List<String> rootList) {
-
-        // Run from the root test class.
-        Set<String> classNamesToRun = new LinkedHashSet<>(rootList);
-        Log.d(CoreTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
-
-        List<Class<?>> classesToRun1 = getClasses(classNamesToRun);
-
-        return new TestList(classesToRun1);
-    }
-
-    private static List<Class<?>> getClasses(Set<String> classNames) {
-        // Populate the list of classes to run.
-        List<Class<?>> classesToRun = new ArrayList<>();
-        for (String className : classNames) {
-            try {
-                classesToRun.add(Class.forName(className));
-            } catch (ClassNotFoundException e) {
-                throw new IllegalStateException("Could not load class '" + className, e);
-            }
-        }
-        return classesToRun;
-    }
-
-    /**
-     * @param classes The list of classes to run.
-     */
-    public TestList(Collection<Class<?>> classes) {
-        this.classesToRun = classes;
-    }
-
-    public void addIncludeTestPackages(Set<String> packageNameSet) {
-        mIncludedPackages.addAll(packageNameSet);
-    }
-
-    public void addExcludeTestPackages(Set<String> packageNameSet) {
-        mExcludedPackages.addAll(packageNameSet);
-    }
-
-    public void addIncludeTests(Set<String> testNameSet) {
-        mIncludedTests.addAll(testNameSet);
-    }
-
-    public void addExcludeTests(Set<String> testNameSet) {
-        mExcludedTests.addAll(testNameSet);
-    }
-
-    /**
-     * Return all the classes to run.
-     */
-    public Class[] getClassesToRun() {
-        return classesToRun.toArray(new Class[classesToRun.size()]);
-    }
-
-    /**
-     * Return true if the test with the specified name should be run, false otherwise.
-     */
-    public boolean shouldRunTest(String testName) {
-
-        int index = testName.indexOf('#');
-        String className;
-        if (index == -1) {
-            className = testName;
-        } else {
-            className = testName.substring(0, index);
-        }
-        try {
-            Class<?> testClass = Class.forName(className);
-            Package testPackage = testClass.getPackage();
-            String testPackageName = "";
-            if (testPackage != null) {
-                testPackageName = testPackage.getName();
-            }
-
-            boolean include =
-                    (mIncludedPackages.isEmpty() || mIncludedPackages.contains(testPackageName)) &&
-                    (mIncludedTests.isEmpty() || mIncludedTests.contains(className) ||
-                            mIncludedTests.contains(testName));
-
-            boolean exclude =
-                    mExcludedPackages.contains(testPackageName) ||
-                    mExcludedTests.contains(className) ||
-                    mExcludedTests.contains(testName);
-
-            return include && !exclude;
-        } catch (ClassNotFoundException e) {
-            Log.w("Could not load class '" + className, e);
-            return false;
-        }
-    }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
deleted file mode 100644
index 91df2b9..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.core.runner.support;
-
-import android.support.test.internal.runner.junit3.AndroidJUnit3Builder;
-import android.support.test.internal.runner.junit3.AndroidSuiteBuilder;
-import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
-import android.support.test.internal.runner.junit4.AndroidJUnit4Builder;
-import android.support.test.internal.util.AndroidRunnerParams;
-
-import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
-import org.junit.internal.builders.AnnotatedBuilder;
-import org.junit.internal.builders.IgnoredBuilder;
-import org.junit.internal.builders.JUnit3Builder;
-import org.junit.internal.builders.JUnit4Builder;
-import org.junit.runners.model.RunnerBuilder;
-
-/**
- * A {@link RunnerBuilder} that can handle all types of tests.
- */
-// A copy of package private class android.support.test.internal.runner.AndroidRunnerBuilder.
-// Copied here so that it can be extended.
-class AndroidRunnerBuilder extends AllDefaultPossibilitiesBuilder {
-
-    private final AndroidJUnit3Builder mAndroidJUnit3Builder;
-    private final AndroidJUnit4Builder mAndroidJUnit4Builder;
-    private final AndroidSuiteBuilder mAndroidSuiteBuilder;
-    private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
-    // TODO: customize for Android ?
-    private final IgnoredBuilder mIgnoredBuilder;
-
-    /**
-     * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
-     */
-    // Added canUseSuiteMethod parameter.
-    AndroidRunnerBuilder(AndroidRunnerParams runnerParams, boolean canUseSuiteMethod) {
-        super(canUseSuiteMethod);
-        mAndroidJUnit3Builder = new AndroidJUnit3Builder(runnerParams);
-        mAndroidJUnit4Builder = new AndroidJUnit4Builder(runnerParams);
-        mAndroidSuiteBuilder = new AndroidSuiteBuilder(runnerParams);
-        mAndroidAnnotatedBuilder = new AndroidAnnotatedBuilder(this, runnerParams);
-        mIgnoredBuilder = new IgnoredBuilder();
-    }
-
-    @Override
-    protected JUnit4Builder junit4Builder() {
-        return mAndroidJUnit4Builder;
-    }
-
-    @Override
-    protected JUnit3Builder junit3Builder() {
-        return mAndroidJUnit3Builder;
-    }
-
-    @Override
-    protected AnnotatedBuilder annotatedBuilder() {
-        return mAndroidAnnotatedBuilder;
-    }
-
-    @Override
-    protected IgnoredBuilder ignoredBuilder() {
-        return mIgnoredBuilder;
-    }
-
-    @Override
-    protected RunnerBuilder suiteMethodBuilder() {
-        return mAndroidSuiteBuilder;
-    }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
deleted file mode 100644
index a2f95e2..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.core.runner.support;
-
-import android.support.test.internal.util.AndroidRunnerParams;
-import android.util.Log;
-import org.junit.runners.model.RunnerBuilder;
-import org.junit.runner.Runner;
-
-/**
- * Extends {@link AndroidRunnerBuilder} in order to provide alternate {@link RunnerBuilder}
- * implementations.
- */
-public class ExtendedAndroidRunnerBuilder extends AndroidRunnerBuilder {
-
-    private static final boolean DEBUG = false;
-
-    private final TestNgRunnerBuilder mTestNgBuilder;
-
-    /**
-     * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
-     */
-    public ExtendedAndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
-        super(runnerParams, false /* CTSv1 filtered out Test suite() classes. */);
-        mTestNgBuilder = new TestNgRunnerBuilder();
-    }
-
-    @Override
-    public Runner runnerForClass(Class<?> testClass) throws Throwable {
-      if (DEBUG) {
-        Log.d("ExAndRunBuild", "runnerForClass: Searching runner for class " + testClass.getName());
-      }
-
-      // Give TestNG tests a chance to participate in the Runner search first.
-      // (Note that the TestNG runner handles log-only runs by itself)
-      Runner runner = mTestNgBuilder.runnerForClass(testClass);
-      if (runner == null) {
-        // Use the normal Runner search mechanism (for Junit tests).
-        runner = super.runnerForClass(testClass);
-      }
-
-      logFoundRunner(runner);
-      return runner;
-    }
-
-    private static void logFoundRunner(Runner runner) {
-      if (DEBUG) {
-        Log.d("ExAndRunBuild", "runnerForClass: Found runner of type " +
-            ((runner == null) ? "<null>" : runner.getClass().getName()));
-      }
-    }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
index 1465bf0..2f084b3 100644
--- a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
@@ -24,9 +24,9 @@
 import org.testng.annotations.Test;
 
 /**
- * A {@link RunnerBuilder} that can TestNG tests.
+ * A {@link RunnerBuilder} that can handle TestNG tests.
  */
-class TestNgRunnerBuilder extends RunnerBuilder {
+public class TestNgRunnerBuilder extends RunnerBuilder {
   // Returns a TestNG runner for this class, only if it is a class
   // annotated with testng's @Test or has any methods with @Test in it.
   @Override
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
deleted file mode 100644
index 3ccec3c..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Contains all the changes needed to the {@code android.support.test.internal.runner} classes.
- *
- * <p>As its name suggests {@code android.support.test.internal.runner} are internal classes that
- * are not designed to be extended from outside those packages. This package encapsulates all the
- * workarounds needed to overcome that limitation, from duplicating classes to using reflection.
- * The intention is that these changes are temporary and they (or a better equivalent) will be
- * quickly integrated into the internal classes.
- */
-package com.android.cts.core.runner.support;
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
deleted file mode 100644
index 08c2a5e..0000000
--- a/tests/expectations/knownfailures.txt
+++ /dev/null
@@ -1,282 +0,0 @@
-[
-{
-  description: "Disable ListeningPortsTest",
-  names: [
-    "android.security.cts.ListeningPortsTest"
-  ],
-  bug: 31803630
-},
-{
-  description: "some AlarmClockTests are not robust across different device types",
-  names: [
-    "android.alarmclock.cts.DismissAlarmTest#testAll",
-    "android.alarmclock.cts.SetAlarmTest#testAll",
-    "android.alarmclock.cts.SnoozeAlarmTest#testAll"
-  ],
-  bug: 23776083
-},
-{
-  description: "the UsageStats is not yet stable enough",
-  names: [
-    "android.app.usage.cts.UsageStatsTest"
-  ],
-  bug: 17536113
-},
-{
-  description: "the ConnectivityConstraintTest are not yet stable",
-  names: [
-    "android.jobscheduler.cts.ConnectivityConstraintTest"
-  ],
-  bug: 18117279
-},
-{
-  description: "tests a fragile by nature as they rely on hardcoded behavior",
-  names: [
-    "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverText",
-    "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverTextExtend"
-  ],
-  bug: 17595050
-},
-{
-  description: "test fails on some devices",
-  names: [
-    "android.dumpsys.cts.DumpsysHostTest#testBatterystatsOutput",
-    "android.dumpsys.cts.DumpsysHostTest#testGfxinfoFramestats"
-  ],
-  bug: 23776893
-},
-{
-  description: "the SSLCertificateSocketFactoryTest often fails because of lack of live internet or short timeout, it should be refactored to do a local server testing",
-  names: [
-    "android.net.cts.SSLCertificateSocketFactoryTest#testCreateSocket",
-    "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_bind",
-    "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_simple",
-    "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_wrapping"
-  ],
-  bug: 18682315
-},
-{
-  description: "the test result are too much dependent on live-internet connection, which for some devices might not exist",
-  names: [
-    "android.net.wifi.cts.NsdManagerTest#testAndroidTestCaseSetupProperly"
-  ],
-  bug: 18680089
-},
-{
-  description: "AudioPolicyBinder tests are not yet robust enough",
-  names: [
-    "android.security.cts.AudioPolicyBinderTest"
-  ],
-  bug: 18461670
-},
-{
-  description: "test not robust",
-  names: [
-    "android.telecom.cts.ExtendedInCallServiceTest#testAddNewOutgoingCallAndThenDisconnect",
-    "android.telecom.cts.RemoteConferenceTest#testRemoteConferenceCallbacks_ConferenceableConnections"
-  ],
-  bug: 23604254
-},
-{
-  description: "tests too flaky",
-  names: [
-    "android.transition.cts.ChangeScrollTest#testChangeScroll"
-  ],
-  bug: 23779020
-},
-{
-  description: "Not all jdwp features are currently supported. These tests will fail",
-  names: [
-    "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch001",
-    "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch002",
-    "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch003",
-    "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch004",
-    "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger001#testDebugger002",
-    "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger002#testDebugger",
-    "org.apache.harmony.jpda.tests.jdwp.Events.ClassUnloadTest#testClassUnloadEvent",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnterTest#testMonitorContendedEnterForClassMatch",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnteredTest#testMonitorContendedEnteredForClassMatch",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassExclude",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchExact",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchFirst",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchSecond",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassOnly",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassExclude",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchExact",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchFirst",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchSecond",
-    "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassOnly",
-    "org.apache.harmony.jpda.tests.jdwp.ReferenceType.ClassFileVersionTest#testClassFileVersion001",
-    "org.apache.harmony.jpda.tests.jdwp.ReferenceType.NestedTypesTest#testNestedTypes001",
-    "org.apache.harmony.jpda.tests.jdwp.ThreadReference.StopTest#testStop001",
-    "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.HoldEventsTest#testHoldEvents001",
-    "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ReleaseEventsTest#testReleaseEvents001"
-  ],
-  bug: 16720689
-},
-{
-  description: "test can only run properly on a user build device when the bug is resolved",
-  names: [
-    "android.appwidget.cts.AppWidgetTest#testAppWidgetProviderCallbacks",
-    "android.appwidget.cts.AppWidgetTest#testBindAppWidget",
-    "android.appwidget.cts.AppWidgetTest#testCollectionWidgets",
-    "android.appwidget.cts.AppWidgetTest#testDeleteHost",
-    "android.appwidget.cts.AppWidgetTest#testDeleteHosts",
-    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetIds",
-    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetInfo",
-    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetOptions",
-    "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetId",
-    "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetIds",
-    "android.appwidget.cts.AppWidgetTest#testTwoAppWidgetProviderCallbacks",
-    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaComponentName",
-    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetId",
-    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetIds"
-  ],
-  bug: 17993121
-},
-{
-  description: "permissions for the API previously used in the test has changed, making it impossible to pass",
-  names: [
-    "android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingFast",
-    "android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingSlow"
-  ],
-  bug: 17394321
-},
-{
-  description: "unexpected failures",
-  names: [
-    "android.openglperf.cts.GlVboPerfTest#testVboWithVaryingIndexBufferNumbers"
-  ],
-  bug: 18091590
-},
-{
-  description: "Test is not yet properly implemented",
-  names: [
-    "android.voicesettings.cts.ZenModeTest#testAll"
-  ],
-  bug: 23238984
-},
-{
-  description: "This test failed on devices that use effect off loading. In addition it uses hidden apis",
-  names: [
-    "android.media.cts.AudioEffectTest#test1_1ConstructorFromUuid"
-  ],
-  bug: 17605875
-},
-{
-  description: "This test failed on hw decoder that doesn't output frame with the configured format.",
-  names: [
-    "android.media.cts.ImageReaderDecoderTest#testHwAVCDecode360pForFlexibleYuv"
-  ],
-  bug: 17144778
-},
-{
-  description: "android.keystore tests will replace these tests",
-  names: [
-    "com.android.org.conscrypt.MacTest#test_getInstance_OpenSSL_ENGINE",
-    "com.android.org.conscrypt.NativeCryptoTest#test_ENGINE_by_id_TestEngine",
-    "com.android.org.conscrypt.SignatureTest#test_getInstance_OpenSSL_ENGINE"
-  ],
-  bug: 18030049
-},
-{
-  description: "The new prepare performance test is not yet passing on all devices",
-  names: [
-    "android.hardware.camera2.cts.SurfaceViewPreviewTest#testPreparePerformance"
-  ],
-  bug: 17989532
-},
-{
-  description: "The timing measurements for preview callbacks are not reliable",
-  names: [
-    "android.hardware.cts.CameraTest#testPreviewFpsRange"
-  ],
-  bug: 23008511
-},
-{
-  description: "Light status bar CTS coming in late",
-  names: [
-    "android.systemui.cts.LightStatusBarTests#testLightStatusBarIcons"
-  ],
-  bug: 23427621
-},
-{
-  description: "tests are not yet ready",
-  names: [
-    "com.android.cts.app.os.OsHostTests#testNonExportedActivities"
-  ],
-  bug: 23779168
-},
-{
-  description: "ConnectivityConstraintTest job scheduler not working.",
-  names: [
-     "android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withWifi",
-     "android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintExecutes_withWifi",
-     "android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withMobile"
-  ],
-  bug: 21262226
-},
-{
-   description: "ConnectivityConstraintTest times out.",
-   names: [
-     "android.jobscheduler.cts.TimingConstraintsTest#testJobParameters_unexpiredDeadline"
-   ],
-   bug: 23144425
-},
-{
-   description: "Video encoding tests are timing out.",
-   names: [
-     "android.media.cts.VideoEncoderTest#testGoogH264FlexArbitraryW",
-     "android.media.cts.VideoEncoderTest#testGoogH264SurfArbitraryW"
-   ],
-   bug: 23827982
-},
-{
-  description: "protected broadcast not working",
-  names: [
-   "android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts"
-  ],
-  bug: 23192492
-},
-{
-  description: "restricted network is not working",
-  names: [
-    "android.net.cts.ConnectivityManagerTest#testRestrictedNetworks"
-  ],
-  bug: 25651805
-},
-{
-  description: "unit testing for MediaPreparer lives within mediastress module",
-  names: [
-    "android.mediastress.cts.preconditions.MediaPreparerTest"
-  ],
-  bug: 25850508
-},
-{
-  description: "Tests for the signature tests should not be in CTS",
-  names: [
-    "android.signature.cts.tests"
-  ],
-  bug: 26150806
-},
-{
-  description: "android.security.cts is using a Non-NDK library, libmedia_jni.so",
-  names: [
-      "android.security.cts.MediaCryptoTest#testMediaCryptoClearKey",
-      "android.security.cts.MediaCryptoTest#testMediaCryptoWidevine"
-  ],
-  bug: 27218502
-},
-{
-  description: "Still investigating this, root cause unknown yet",
-  bug: 27578806,
-  names: ["com.android.cts.cpptools.RunAsHostTest#testRunAs"]
-},
-{
-  description: "Wired headset tests are no longer a requirement per CDD",
-  names: [
-    "android.telecom.cts.WiredHeadsetTest"
-  ],
-  bug: 26149528
-}
-]
diff --git a/tests/libcore/jsr166/AndroidManifest.xml b/tests/libcore/jsr166/AndroidManifest.xml
index baae488..5fd3f6e 100644
--- a/tests/libcore/jsr166/AndroidManifest.xml
+++ b/tests/libcore/jsr166/AndroidManifest.xml
@@ -22,6 +22,9 @@
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.libcore.cts.jsr166"
-                     android:label="CTS Libcore JSR166 test cases" />
+                     android:label="CTS Libcore JSR166 test cases">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
 
 </manifest>
diff --git a/tests/libcore/jsr166/AndroidTest.xml b/tests/libcore/jsr166/AndroidTest.xml
index 2a3e5d2..0c67705 100644
--- a/tests/libcore/jsr166/AndroidTest.xml
+++ b/tests/libcore/jsr166/AndroidTest.xml
@@ -27,8 +27,6 @@
     </target_preparer>
     <test class="com.android.compatibility.testtype.LibcoreTest" >
         <option name="package" value="android.libcore.cts.jsr166" />
-        <option name="instrumentation-arg" key="listener"
-                value="com.android.cts.runner.CtsTestRunListener" />
         <option name="instrumentation-arg" key="filter"
                 value="com.android.cts.core.runner.ExpectationBasedFilter" />
         <option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/luni/AndroidManifest.xml b/tests/libcore/luni/AndroidManifest.xml
index 0389be6..4df4b93 100644
--- a/tests/libcore/luni/AndroidManifest.xml
+++ b/tests/libcore/luni/AndroidManifest.xml
@@ -23,6 +23,9 @@
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.libcore.cts"
-                     android:label="CTS Libcore test cases" />
+                     android:label="CTS Libcore test cases">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
 
 </manifest>
diff --git a/tests/libcore/luni/AndroidTest.xml b/tests/libcore/luni/AndroidTest.xml
index a8c4142..fa1c9cc 100644
--- a/tests/libcore/luni/AndroidTest.xml
+++ b/tests/libcore/luni/AndroidTest.xml
@@ -27,8 +27,6 @@
     </target_preparer>
     <test class="com.android.compatibility.testtype.LibcoreTest" >
         <option name="package" value="android.libcore.cts" />
-        <option name="instrumentation-arg" key="listener"
-                value="com.android.cts.runner.CtsTestRunListener" />
         <option name="instrumentation-arg" key="filter"
                 value="com.android.cts.core.runner.ExpectationBasedFilter" />
         <option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/ojluni/AndroidManifest.xml b/tests/libcore/ojluni/AndroidManifest.xml
index 5f900a9..8c45c30 100644
--- a/tests/libcore/ojluni/AndroidManifest.xml
+++ b/tests/libcore/ojluni/AndroidManifest.xml
@@ -18,9 +18,12 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.libcore.cts.oj">
     <uses-permission android:name="android.permission.INTERNET" />
 
-    <!-- important: instrument another package which actually contains the CTS core test runner -->
-    <instrumentation android:name="com.android.cts.core.runner.CoreTestRunner"
+    <!-- important: instrument another package which actually contains AJUR -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.libcore.runner"
-                     android:label="CTS Libcore OJ test cases" />
+                     android:label="CTS Libcore OJ test cases">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
 
 </manifest>
diff --git a/tests/libcore/ojluni/AndroidTest.xml b/tests/libcore/ojluni/AndroidTest.xml
index 9bf7113..2b7ae29 100644
--- a/tests/libcore/ojluni/AndroidTest.xml
+++ b/tests/libcore/ojluni/AndroidTest.xml
@@ -22,17 +22,17 @@
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <!-- this has the CoreTestRunner which needs to be in a separate APK -->
+        <!-- this has the AJUR which needs to be in a separate APK -->
         <option name="test-file-name" value="CtsLibcoreTestRunner.apk" />
         <!-- this has just the instrumentation which acts as the tests we want to run -->
         <option name="test-file-name" value="CtsLibcoreOjTestCases.apk" />
     </target_preparer>
     <test class="com.android.compatibility.testtype.LibcoreTest" >
-        <!-- override AJUR -->
-        <option name="runner" value="com.android.cts.core.runner.CoreTestRunner" />
         <option name="package" value="android.libcore.cts.oj" />
-        <option name="instrumentation-arg" key="core-listener"
-                value="com.android.cts.runner.CtsTestRunListener"/>
+        <option name="instrumentation-arg" key="runnerBuilder"
+                value="com.android.cts.core.runner.support.TestNgRunnerBuilder"/>
+        <option name="instrumentation-arg" key="filter"
+                value="com.android.cts.core.runner.ExpectationBasedFilter" />
         <option name="core-expectation" value="/knownfailures.txt" />
         <option name="runtime-hint" value="35m"/>
         <!-- 20x default timeout of 600sec -->
diff --git a/tests/libcore/okhttp/AndroidManifest.xml b/tests/libcore/okhttp/AndroidManifest.xml
index 151fda9..a96448d 100644
--- a/tests/libcore/okhttp/AndroidManifest.xml
+++ b/tests/libcore/okhttp/AndroidManifest.xml
@@ -23,6 +23,9 @@
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.libcore.cts.okhttp"
-                     android:label="CTS Libcore OkHttp test cases" />
+                     android:label="CTS Libcore OkHttp test cases">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
 
 </manifest>
diff --git a/tests/libcore/okhttp/AndroidTest.xml b/tests/libcore/okhttp/AndroidTest.xml
index 4e79b80..c3470cc 100644
--- a/tests/libcore/okhttp/AndroidTest.xml
+++ b/tests/libcore/okhttp/AndroidTest.xml
@@ -27,8 +27,6 @@
     </target_preparer>
     <test class="com.android.compatibility.testtype.LibcoreTest" >
         <option name="package" value="android.libcore.cts.okhttp" />
-        <option name="instrumentation-arg" key="listener"
-                value="com.android.cts.runner.CtsTestRunListener" />
         <option name="instrumentation-arg" key="filter"
                 value="com.android.cts.core.runner.ExpectationBasedFilter" />
         <option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/wycheproof-bc/AndroidManifest.xml b/tests/libcore/wycheproof-bc/AndroidManifest.xml
index 15c5fd5..fb53977 100644
--- a/tests/libcore/wycheproof-bc/AndroidManifest.xml
+++ b/tests/libcore/wycheproof-bc/AndroidManifest.xml
@@ -23,6 +23,9 @@
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.libcore.cts.wycheproof.bouncycastle"
-                     android:label="CTS Libcore Wycheproof Bouncy Castle test cases" />
+                     android:label="CTS Libcore Wycheproof Bouncy Castle test cases">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
 
 </manifest>
diff --git a/tests/libcore/wycheproof-bc/AndroidTest.xml b/tests/libcore/wycheproof-bc/AndroidTest.xml
index 9c3a50a..ac761f3 100644
--- a/tests/libcore/wycheproof-bc/AndroidTest.xml
+++ b/tests/libcore/wycheproof-bc/AndroidTest.xml
@@ -26,8 +26,6 @@
              context of one of the suites, so we have to limit the test
              infrastructure to only running the test suites. -->
         <option name="test-package" value="android.libcore.cts.wycheproof" />
-        <option name="instrumentation-arg" key="listener"
-                value="com.android.cts.runner.CtsTestRunListener" />
         <option name="instrumentation-arg" key="filter"
                 value="com.android.cts.core.runner.ExpectationBasedFilter" />
         <option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/wycheproof/AndroidManifest.xml b/tests/libcore/wycheproof/AndroidManifest.xml
index 765c677..5e8058f 100644
--- a/tests/libcore/wycheproof/AndroidManifest.xml
+++ b/tests/libcore/wycheproof/AndroidManifest.xml
@@ -23,6 +23,9 @@
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.libcore.cts.wycheproof.conscrypt"
-                     android:label="CTS Libcore Wycheproof Conscrypt test cases" />
+                     android:label="CTS Libcore Wycheproof Conscrypt test cases">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
 
 </manifest>
diff --git a/tests/libcore/wycheproof/AndroidTest.xml b/tests/libcore/wycheproof/AndroidTest.xml
index b5874fd..0c713b9 100644
--- a/tests/libcore/wycheproof/AndroidTest.xml
+++ b/tests/libcore/wycheproof/AndroidTest.xml
@@ -26,8 +26,6 @@
              context of one of the suites, so we have to limit the test
              infrastructure to only running the test suites. -->
         <option name="test-package" value="android.libcore.cts.wycheproof" />
-        <option name="instrumentation-arg" key="listener"
-                value="com.android.cts.runner.CtsTestRunListener" />
         <option name="instrumentation-arg" key="filter"
                 value="com.android.cts.core.runner.ExpectationBasedFilter" />
         <option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/pdf/res/raw/protected_pdf.pdf b/tests/pdf/res/raw/protected_pdf.pdf
new file mode 100644
index 0000000..e4092b9
--- /dev/null
+++ b/tests/pdf/res/raw/protected_pdf.pdf
Binary files differ
diff --git a/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
index 2f0158e..2ce69d1 100644
--- a/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
+++ b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
@@ -62,6 +62,7 @@
     private static final int A5_PORTRAIT_PRINTSCALING_NONE =
             R.raw.a5_portrait_rgbb_1_6_printscaling_none;
     private static final int TWO_PAGES = R.raw.two_pages;
+    private static final int PROTECTED_PDF = R.raw.protected_pdf;
 
     private Context mContext;
 
@@ -76,12 +77,28 @@
     }
 
     @Test
-    @Ignore("Makes all subsequent tests fail")
     public void constructRendererFromNonPDF() throws Exception {
         // Open jpg as if it was a PDF
-        ParcelFileDescriptor fd = mContext.getResources().openRawResourceFd(R.raw.testimage)
-                .getParcelFileDescriptor();
-        verifyException(() -> new PdfRenderer(fd), IOException.class);
+        verifyException(() -> createRenderer(R.raw.testimage, mContext), IOException.class);
+    }
+
+    @Test
+    public void constructRendererFromProtectedPDF() throws Exception {
+        verifyException(() -> createRenderer(PROTECTED_PDF, mContext), SecurityException.class);
+    }
+
+    @Test
+    public void rendererRecoversAfterFailure() throws Exception {
+        // Create rendered to prevent lib from being unloaded
+        PdfRenderer firstRenderer = createRenderer(A4_PORTRAIT, mContext);
+
+        verifyException(() -> createRenderer(PROTECTED_PDF, mContext), SecurityException.class);
+
+        // We can create new renderers after we failed to create one
+        PdfRenderer renderer = createRenderer(TWO_PAGES, mContext);
+        renderer.close();
+
+        firstRenderer.close();
     }
 
     @Test
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
index df69004..b382698 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
+++ b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
@@ -19,6 +19,6 @@
 LOCAL_PACKAGE_NAME := CtsApacheHttpLegacyCurrentApiSignatureTestCases
 
 LOCAL_SIGNATURE_API_FILES := \
-    apache-http-legacy-current.api \
+    apache-http-legacy-minus-current.api \
 
 include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
index a5e69a9..a9db2b0 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
@@ -20,7 +20,7 @@
         <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="apache-http-legacy-current.api->/data/local/tmp/signature-test/apache-http-legacy-current.api" />
+        <option name="push" value="apache-http-legacy-minus-current.api->/data/local/tmp/signature-test/apache-http-legacy-minus-current.api" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
@@ -29,7 +29,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.apache_http_legacy_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-current.api" />
+        <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-minus-current.api" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
index 08cc051..062c41f 100644
--- a/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
+++ b/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
@@ -55,6 +55,9 @@
         KNOWN_INACCESSIBLE_CLASSES.add("android.os.UserManager.UserRestrictionSource");
         KNOWN_INACCESSIBLE_CLASSES.add(
                 "android.service.persistentdata.PersistentDataBlockManager.FlashLockState");
+        KNOWN_INACCESSIBLE_CLASSES.add("android.hardware.radio.ProgramSelector.IdentifierType");
+        KNOWN_INACCESSIBLE_CLASSES.add("android.hardware.radio.ProgramSelector.ProgramType");
+        KNOWN_INACCESSIBLE_CLASSES.add("android.hardware.radio.RadioManager.Band");
     }
 
     private TestResultObserver mResultObserver;
diff --git a/tests/signature/api/Android.mk b/tests/signature/api/Android.mk
index 29328cb..05aa3c0 100644
--- a/tests/signature/api/Android.mk
+++ b/tests/signature/api/Android.mk
@@ -66,11 +66,28 @@
 
 include $(LOCAL_PATH)/build_xml_api_file.mk
 
-# current apache-http-legacy api, in XML format.
-# ==============================================
+# current apache-http-legacy minus current api, in text format.
+# =============================================================
+# Removes any classes from the org.apache.http.legacy API description that are
+# also part of the Android API description.
 include $(CLEAR_VARS)
-LOCAL_MODULE := cts-apache-http-legacy-current-api
-LOCAL_MODULE_STEM := apache-http-legacy-current.api
-LOCAL_SRC_FILES := external/apache-http/api/apache-http-legacy-current.txt
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_ETC)
 
-include $(LOCAL_PATH)/build_xml_api_file.mk
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_MODULE := cts-apache-http-legacy-minus-current-api
+LOCAL_MODULE_STEM := apache-http-legacy-minus-current.api
+
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE) : \
+        frameworks/base/api/current.txt \
+        external/apache-http/api/apache-http-legacy-current.txt \
+        | $(APICHECK)
+	@echo "Generate unique Apache Http Legacy API file -> $@"
+	@mkdir -p $(dir $@)
+	$(hide) $(APICHECK_COMMAND) -new_api_no_strip \
+	        frameworks/base/api/current.txt \
+            external/apache-http/api/apache-http-legacy-current.txt \
+            $@
diff --git a/tests/tests/debug/Android.mk b/tests/tests/debug/Android.mk
index f1b9b27..c715d07 100644
--- a/tests/tests/debug/Android.mk
+++ b/tests/tests/debug/Android.mk
@@ -30,7 +30,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner nativetesthelper
 
 LOCAL_JNI_SHARED_LIBRARIES := libdebugtest
 
diff --git a/tests/tests/debug/AndroidManifest.xml b/tests/tests/debug/AndroidManifest.xml
index 4b3254a..091e778 100644
--- a/tests/tests/debug/AndroidManifest.xml
+++ b/tests/tests/debug/AndroidManifest.xml
@@ -26,8 +26,6 @@
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.debug.cts"
                      android:label="CTS tests of native debugging API">
-        <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
 
 </manifest>
diff --git a/tests/tests/debug/libdebugtest/Android.mk b/tests/tests/debug/libdebugtest/Android.mk
index 65c9756..aca41a3 100644
--- a/tests/tests/debug/libdebugtest/Android.mk
+++ b/tests/tests/debug/libdebugtest/Android.mk
@@ -29,6 +29,7 @@
 	android_debug_cts.cpp
 
 LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_WHOLE_STATIC_LIBRARIES := libnativetesthelper_jni
 
 LOCAL_SDK_VERSION := 23
 LOCAL_NDK_STL_VARIANT := c++_static
diff --git a/tests/tests/debug/libdebugtest/android_debug_cts.cpp b/tests/tests/debug/libdebugtest/android_debug_cts.cpp
index 2c7c967..6ea8324 100644
--- a/tests/tests/debug/libdebugtest/android_debug_cts.cpp
+++ b/tests/tests/debug/libdebugtest/android_debug_cts.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <jni.h>
+#include <gtest/gtest.h>
 #include <android/log.h>
 
 #include <sys/ptrace.h>
@@ -28,6 +29,7 @@
 
 #define LOG_TAG "Cts-DebugTest"
 
+// Used by child processes only
 #define assert_or_exit(x)                                                                         \
     do {                                                                                          \
         if(x) break;                                                                              \
@@ -35,29 +37,21 @@
                 errno, strerror(errno));                                                          \
         _exit(1);                                                                                 \
     } while (0)
-#define assert_or_return(x)                                                                       \
-    do {                                                                                          \
-        if(x) break;                                                                              \
-        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Assertion " #x " failed. errno(%d): %s", \
-                errno, strerror(errno));                                                          \
-        return false;                                                                             \
-    } while (0)
 
-static bool parent(pid_t child) {
+static void parent(pid_t child) {
     int status;
     int wpid = waitpid(child, &status, 0);
-    assert_or_return(wpid == child);
-    assert_or_return(WIFEXITED(status));
-    assert_or_return(WEXITSTATUS(status ) == 0);
-    return true;
+    ASSERT_EQ(child, wpid);
+    ASSERT_TRUE(WIFEXITED(status));
+    ASSERT_EQ(0, WEXITSTATUS(status));
 }
 
-static bool run_test(const std::function<void(pid_t)> &test) {
+static void run_test(const std::function<void(pid_t)> &test) {
     pid_t pid = fork();
-    assert_or_return(pid >= 0);
-    if (pid != 0)
-        return parent(pid);
-    else {
+    ASSERT_NE(-1, pid) << "fork() failed with " << strerror(errno);
+    if (pid != 0) {
+        parent(pid);
+    } else {
         // child
         test(getppid());
         _exit(0);
@@ -74,12 +68,10 @@
     assert_or_exit(ptrace(PTRACE_DETACH, parent, nullptr, nullptr) == 0);
 }
 
-// public static native boolean ptraceAttach();
-extern "C" jboolean Java_android_debug_cts_DebugTest_ptraceAttach(JNIEnv *, jclass) {
-    return run_test(ptraceAttach);
+TEST(DebugTest, ptraceAttach) {
+    run_test(ptraceAttach);
 }
 
-
 static void processVmReadv(pid_t parent, const std::vector<long *> &addresses) {
     long destination;
     iovec local = { &destination, sizeof destination };
@@ -98,11 +90,11 @@
 
 static long global_variable = 0x47474747;
 // public static native boolean processVmReadv();
-extern "C" jboolean Java_android_debug_cts_DebugTest_processVmReadv(JNIEnv *, jclass) {
+TEST(DebugTest, processVmReadv) {
     long stack_variable = 0x42424242;
     // This runs the test with a selection of different kinds of addresses and
     // makes sure the child process (simulating a debugger) can read them.
-    return run_test([&](pid_t parent) {
+    run_test([&](pid_t parent) {
         processVmReadv(parent, std::vector<long *>{
                                    &global_variable, &stack_variable,
                                    reinterpret_cast<long *>(&processVmReadv)});
@@ -110,9 +102,9 @@
 }
 
 // public static native boolean processVmReadvNullptr();
-extern "C" jboolean Java_android_debug_cts_DebugTest_processVmReadvNullptr(JNIEnv *, jclass) {
+TEST(DebugTest, processVmReadvNullptr) {
     // Make sure reading unallocated memory behaves reasonably.
-    return run_test([](pid_t parent) {
+    run_test([](pid_t parent) {
         long destination;
         iovec local = {&destination, sizeof destination};
         iovec remote = {nullptr, sizeof(long)};
diff --git a/tests/tests/debug/src/android/debug/cts/DebugTest.java b/tests/tests/debug/src/android/debug/cts/DebugTest.java
index ca55d9c..993f02b 100644
--- a/tests/tests/debug/src/android/debug/cts/DebugTest.java
+++ b/tests/tests/debug/src/android/debug/cts/DebugTest.java
@@ -16,26 +16,10 @@
 
 package android.debug.cts;
 
-import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import com.android.gtestrunner.GtestRunner;
+import com.android.gtestrunner.TargetLibrary;
 
-public class DebugTest extends TestCase {
-
-    static {
-        System.loadLibrary("debugtest");
-    }
-
-    public static native boolean ptraceAttach();
-    public void test_ptraceAttach() {
-        assertEquals(true, ptraceAttach());
-    }
-
-    public static native boolean processVmReadv();
-    public void test_processVmReadv() {
-        assertEquals(true, processVmReadv());
-    }
-
-    public static native boolean processVmReadvNullptr();
-    public void test_processVmReadvNullptr() {
-        assertEquals(true, processVmReadvNullptr());
-    }
-}
+@RunWith(GtestRunner.class)
+@TargetLibrary("debugtest")
+public class DebugTest {}
diff --git a/tests/tests/graphics/assets/a3em.ttx b/tests/tests/graphics/assets/a3em.ttx
new file mode 100644
index 0000000..d3b9e16
--- /dev/null
+++ b/tests/tests/graphics/assets/a3em.ttx
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+  <GlyphOrder>
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="1em"/>
+    <GlyphID id="2" name="3em"/>
+  </GlyphOrder>
+
+  <head>
+    <tableVersion value="1.0"/>
+    <fontRevision value="1.0"/>
+    <checkSumAdjustment value="0x640cdb2f"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00000011"/>
+    <unitsPerEm value="1000"/>
+    <created value="Fri Mar 17 07:26:00 2017"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="7"/>
+    <fontDirectionHint value="2"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="1.0"/>
+    <ascent value="1000"/>
+    <descent value="-200"/>
+    <lineGap value="0"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+  </hhea>
+
+  <maxp>
+    <tableVersion value="0x10000"/>
+    <maxZones value="0"/>
+    <maxTwilightPoints value="0"/>
+    <maxStorage value="0"/>
+    <maxFunctionDefs value="0"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="0"/>
+    <maxSizeOfInstructions value="0"/>
+    <maxComponentElements value="0"/>
+  </maxp>
+
+  <OS_2>
+    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+         will be recalculated by the compiler -->
+    <version value="3"/>
+    <xAvgCharWidth value="594"/>
+    <usWeightClass value="400"/>
+    <usWidthClass value="5"/>
+    <fsType value="00000000 00001000"/>
+    <ySubscriptXSize value="650"/>
+    <ySubscriptYSize value="600"/>
+    <ySubscriptXOffset value="0"/>
+    <ySubscriptYOffset value="75"/>
+    <ySuperscriptXSize value="650"/>
+    <ySuperscriptYSize value="600"/>
+    <ySuperscriptXOffset value="0"/>
+    <ySuperscriptYOffset value="350"/>
+    <yStrikeoutSize value="50"/>
+    <yStrikeoutPosition value="300"/>
+    <sFamilyClass value="0"/>
+    <panose>
+      <bFamilyType value="0"/>
+      <bSerifStyle value="0"/>
+      <bWeight value="5"/>
+      <bProportion value="0"/>
+      <bContrast value="0"/>
+      <bStrokeVariation value="0"/>
+      <bArmStyle value="0"/>
+      <bLetterForm value="0"/>
+      <bMidline value="0"/>
+      <bXHeight value="0"/>
+    </panose>
+    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+    <achVendID value="UKWN"/>
+    <fsSelection value="00000000 01000000"/>
+    <usFirstCharIndex value="32"/>
+    <usLastCharIndex value="122"/>
+    <sTypoAscender value="800"/>
+    <sTypoDescender value="-200"/>
+    <sTypoLineGap value="200"/>
+    <usWinAscent value="1000"/>
+    <usWinDescent value="200"/>
+    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+    <sxHeight value="500"/>
+    <sCapHeight value="700"/>
+    <usDefaultChar value="0"/>
+    <usBreakChar value="32"/>
+    <usMaxContext value="0"/>
+  </OS_2>
+
+  <hmtx>
+    <mtx name=".notdef" width="500" lsb="93"/>
+    <mtx name="1em" width="1000" lsb="93"/>
+    <mtx name="3em" width="3000" lsb="93"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_4 platformID="3" platEncID="10" language="0">
+      <map code="0x0061" name="3em" />
+      <map code="0x0062" name="1em" />
+      <map code="0x0063" name="1em" />
+      <map code="0x0064" name="1em" />
+      <map code="0x0065" name="1em" />
+    </cmap_format_4>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+  </glyf>
+
+  <name>
+    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+      Copyright (C) 2017 The Android Open Source Project
+    </namerecord>
+    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+      SampleFont-Regular
+    </namerecord>
+    <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      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.
+    </namerecord>
+    <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+      http://www.apache.org/licenses/LICENSE-2.0
+    </namerecord>
+  </name>
+
+  <post>
+    <formatType value="3.0"/>
+    <italicAngle value="0.0"/>
+    <underlinePosition value="-75"/>
+    <underlineThickness value="50"/>
+    <isFixedPitch value="0"/>
+    <minMemType42 value="0"/>
+    <maxMemType42 value="0"/>
+    <minMemType1 value="0"/>
+    <maxMemType1 value="0"/>
+  </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/assets/b3em.ttx b/tests/tests/graphics/assets/b3em.ttx
new file mode 100644
index 0000000..b5a77ef
--- /dev/null
+++ b/tests/tests/graphics/assets/b3em.ttx
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+  <GlyphOrder>
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="1em"/>
+    <GlyphID id="2" name="3em"/>
+  </GlyphOrder>
+
+  <head>
+    <tableVersion value="1.0"/>
+    <fontRevision value="1.0"/>
+    <checkSumAdjustment value="0x640cdb2f"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00000011"/>
+    <unitsPerEm value="1000"/>
+    <created value="Fri Mar 17 07:26:00 2017"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="7"/>
+    <fontDirectionHint value="2"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="1.0"/>
+    <ascent value="1000"/>
+    <descent value="-200"/>
+    <lineGap value="0"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+  </hhea>
+
+  <maxp>
+    <tableVersion value="0x10000"/>
+    <maxZones value="0"/>
+    <maxTwilightPoints value="0"/>
+    <maxStorage value="0"/>
+    <maxFunctionDefs value="0"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="0"/>
+    <maxSizeOfInstructions value="0"/>
+    <maxComponentElements value="0"/>
+  </maxp>
+
+  <OS_2>
+    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+         will be recalculated by the compiler -->
+    <version value="3"/>
+    <xAvgCharWidth value="594"/>
+    <usWeightClass value="400"/>
+    <usWidthClass value="5"/>
+    <fsType value="00000000 00001000"/>
+    <ySubscriptXSize value="650"/>
+    <ySubscriptYSize value="600"/>
+    <ySubscriptXOffset value="0"/>
+    <ySubscriptYOffset value="75"/>
+    <ySuperscriptXSize value="650"/>
+    <ySuperscriptYSize value="600"/>
+    <ySuperscriptXOffset value="0"/>
+    <ySuperscriptYOffset value="350"/>
+    <yStrikeoutSize value="50"/>
+    <yStrikeoutPosition value="300"/>
+    <sFamilyClass value="0"/>
+    <panose>
+      <bFamilyType value="0"/>
+      <bSerifStyle value="0"/>
+      <bWeight value="5"/>
+      <bProportion value="0"/>
+      <bContrast value="0"/>
+      <bStrokeVariation value="0"/>
+      <bArmStyle value="0"/>
+      <bLetterForm value="0"/>
+      <bMidline value="0"/>
+      <bXHeight value="0"/>
+    </panose>
+    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+    <achVendID value="UKWN"/>
+    <fsSelection value="00000000 01000000"/>
+    <usFirstCharIndex value="32"/>
+    <usLastCharIndex value="122"/>
+    <sTypoAscender value="800"/>
+    <sTypoDescender value="-200"/>
+    <sTypoLineGap value="200"/>
+    <usWinAscent value="1000"/>
+    <usWinDescent value="200"/>
+    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+    <sxHeight value="500"/>
+    <sCapHeight value="700"/>
+    <usDefaultChar value="0"/>
+    <usBreakChar value="32"/>
+    <usMaxContext value="0"/>
+  </OS_2>
+
+  <hmtx>
+    <mtx name=".notdef" width="500" lsb="93"/>
+    <mtx name="1em" width="1000" lsb="93"/>
+    <mtx name="3em" width="3000" lsb="93"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_4 platformID="3" platEncID="10" language="0">
+      <map code="0x0061" name="1em" />
+      <map code="0x0062" name="3em" />
+      <map code="0x0063" name="1em" />
+      <map code="0x0064" name="1em" />
+      <map code="0x0065" name="1em" />
+    </cmap_format_4>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+  </glyf>
+
+  <name>
+    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+      Copyright (C) 2017 The Android Open Source Project
+    </namerecord>
+    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+      SampleFont-Regular
+    </namerecord>
+    <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      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.
+    </namerecord>
+    <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+      http://www.apache.org/licenses/LICENSE-2.0
+    </namerecord>
+  </name>
+
+  <post>
+    <formatType value="3.0"/>
+    <italicAngle value="0.0"/>
+    <underlinePosition value="-75"/>
+    <underlineThickness value="50"/>
+    <isFixedPitch value="0"/>
+    <minMemType42 value="0"/>
+    <maxMemType42 value="0"/>
+    <minMemType1 value="0"/>
+    <maxMemType1 value="0"/>
+  </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/assets/c3em.ttx b/tests/tests/graphics/assets/c3em.ttx
new file mode 100644
index 0000000..f5ed8e5
--- /dev/null
+++ b/tests/tests/graphics/assets/c3em.ttx
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+  <GlyphOrder>
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="1em"/>
+    <GlyphID id="2" name="3em"/>
+  </GlyphOrder>
+
+  <head>
+    <tableVersion value="1.0"/>
+    <fontRevision value="1.0"/>
+    <checkSumAdjustment value="0x640cdb2f"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00000011"/>
+    <unitsPerEm value="1000"/>
+    <created value="Fri Mar 17 07:26:00 2017"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="7"/>
+    <fontDirectionHint value="2"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="1.0"/>
+    <ascent value="1000"/>
+    <descent value="-200"/>
+    <lineGap value="0"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+  </hhea>
+
+  <maxp>
+    <tableVersion value="0x10000"/>
+    <maxZones value="0"/>
+    <maxTwilightPoints value="0"/>
+    <maxStorage value="0"/>
+    <maxFunctionDefs value="0"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="0"/>
+    <maxSizeOfInstructions value="0"/>
+    <maxComponentElements value="0"/>
+  </maxp>
+
+  <OS_2>
+    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+         will be recalculated by the compiler -->
+    <version value="3"/>
+    <xAvgCharWidth value="594"/>
+    <usWeightClass value="400"/>
+    <usWidthClass value="5"/>
+    <fsType value="00000000 00001000"/>
+    <ySubscriptXSize value="650"/>
+    <ySubscriptYSize value="600"/>
+    <ySubscriptXOffset value="0"/>
+    <ySubscriptYOffset value="75"/>
+    <ySuperscriptXSize value="650"/>
+    <ySuperscriptYSize value="600"/>
+    <ySuperscriptXOffset value="0"/>
+    <ySuperscriptYOffset value="350"/>
+    <yStrikeoutSize value="50"/>
+    <yStrikeoutPosition value="300"/>
+    <sFamilyClass value="0"/>
+    <panose>
+      <bFamilyType value="0"/>
+      <bSerifStyle value="0"/>
+      <bWeight value="5"/>
+      <bProportion value="0"/>
+      <bContrast value="0"/>
+      <bStrokeVariation value="0"/>
+      <bArmStyle value="0"/>
+      <bLetterForm value="0"/>
+      <bMidline value="0"/>
+      <bXHeight value="0"/>
+    </panose>
+    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+    <achVendID value="UKWN"/>
+    <fsSelection value="00000000 01000000"/>
+    <usFirstCharIndex value="32"/>
+    <usLastCharIndex value="122"/>
+    <sTypoAscender value="800"/>
+    <sTypoDescender value="-200"/>
+    <sTypoLineGap value="200"/>
+    <usWinAscent value="1000"/>
+    <usWinDescent value="200"/>
+    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+    <sxHeight value="500"/>
+    <sCapHeight value="700"/>
+    <usDefaultChar value="0"/>
+    <usBreakChar value="32"/>
+    <usMaxContext value="0"/>
+  </OS_2>
+
+  <hmtx>
+    <mtx name=".notdef" width="500" lsb="93"/>
+    <mtx name="1em" width="1000" lsb="93"/>
+    <mtx name="3em" width="3000" lsb="93"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_4 platformID="3" platEncID="10" language="0">
+      <map code="0x0061" name="1em" />
+      <map code="0x0062" name="1em" />
+      <map code="0x0063" name="3em" />
+      <map code="0x0064" name="1em" />
+      <map code="0x0065" name="1em" />
+    </cmap_format_4>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+  </glyf>
+
+  <name>
+    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+      Copyright (C) 2017 The Android Open Source Project
+    </namerecord>
+    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+      SampleFont-Regular
+    </namerecord>
+    <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      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.
+    </namerecord>
+    <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+      http://www.apache.org/licenses/LICENSE-2.0
+    </namerecord>
+  </name>
+
+  <post>
+    <formatType value="3.0"/>
+    <italicAngle value="0.0"/>
+    <underlinePosition value="-75"/>
+    <underlineThickness value="50"/>
+    <isFixedPitch value="0"/>
+    <minMemType42 value="0"/>
+    <maxMemType42 value="0"/>
+    <minMemType1 value="0"/>
+    <maxMemType1 value="0"/>
+  </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png
index 38339b7..32a7516 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
index be487d1..6cafa84 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png
index 943fce5..b0b6eb5 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png
index b46363e..9f60a31 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
index 01c445c..452e3ab 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
index 739eea1..767a3e1 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
index 4617f62..48bccdb 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
index 4d6b84d..680bb70 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
index c6540e8..ccdd69d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
index 491e73e..4e5ff8c 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
index e335a92..65a7131 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
index 57f2ae3..3a0d00b 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
index e74c181..c9702c9 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png
index 7450751..b0af7d4 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
index d010d79..e779718 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
index 5ada060..2fbf79d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
index 5af7090..060c4b9 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
index 24b9662..b8fe74d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
index c9677a6..9e92c8a 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
index 8882a7a..0262e57 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
index 143ce3e..1520397 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
index 9a5efd2..727bb48 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png
index 2edc3c7..d68ab90 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png
index 9822bc2..2830840 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png
index d12b142..b5d25be 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png
index 3936c89..923347d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png
index c5d06f6..74c30fa 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
index 3936c89..923347d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png
index c5d06f6..74c30fa 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png
index 2bf7882..c202ffc 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
index 4141d6f..ed31e47 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png
index 1212fb3..a32de90 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
index 0717399..66e4e3b 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
index 505aa2e..9aeeeef 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
index 9b53e94..468a1c3 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png
index a5d4d33..e4bc055 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png
index 0d8ded1..bb185f2 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png
index 3da7969..02901b6 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/font/a3em.ttf b/tests/tests/graphics/res/font/a3em.ttf
new file mode 100644
index 0000000..a601ce2
--- /dev/null
+++ b/tests/tests/graphics/res/font/a3em.ttf
Binary files differ
diff --git a/tests/tests/graphics/res/font/b3em.ttf b/tests/tests/graphics/res/font/b3em.ttf
new file mode 100644
index 0000000..63948a2
--- /dev/null
+++ b/tests/tests/graphics/res/font/b3em.ttf
Binary files differ
diff --git a/tests/tests/graphics/res/font/c3em.ttf b/tests/tests/graphics/res/font/c3em.ttf
new file mode 100644
index 0000000..badc3e2
--- /dev/null
+++ b/tests/tests/graphics/res/font/c3em.ttf
Binary files differ
diff --git a/tests/tests/graphics/res/font/multistyle_family.xml b/tests/tests/graphics/res/font/multistyle_family.xml
new file mode 100644
index 0000000..2522e72
--- /dev/null
+++ b/tests/tests/graphics/res/font/multistyle_family.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+    <font android:font="@font/a3em" android:fontWeight="400" android:fontStyle="normal" />
+    <font android:font="@font/b3em" android:fontWeight="400" android:fontStyle="italic" />
+    <font android:font="@font/c3em" android:fontWeight="700" android:fontStyle="italic" />
+</font-family>
diff --git a/tests/tests/graphics/res/font/multiweight_family.xml b/tests/tests/graphics/res/font/multiweight_family.xml
new file mode 100644
index 0000000..2ed0490
--- /dev/null
+++ b/tests/tests/graphics/res/font/multiweight_family.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+    <font android:font="@font/a3em" android:fontWeight="100" android:fontStyle="normal" />
+    <font android:font="@font/b3em" android:fontWeight="400" android:fontStyle="normal" />
+    <font android:font="@font/c3em" android:fontWeight="700" android:fontStyle="normal" />
+</font-family>
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
index ba90c0f..97064b0 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
@@ -52,6 +52,19 @@
     private static final String DEFAULT = (String)null;
     private static final String INVALID = "invalid-family-name";
 
+    private static final float GLYPH_1EM_WIDTH;
+    private static final float GLYPH_3EM_WIDTH;
+
+    static {
+        // 3em.ttf supports "a", "b", "c". The width of "a" is 3em, others are 1em.
+        final Context ctx = InstrumentationRegistry.getTargetContext();
+        final Typeface typeface = ctx.getResources().getFont(R.font.a3em);
+        final Paint paint = new Paint();
+        paint.setTypeface(typeface);
+        GLYPH_3EM_WIDTH = paint.measureText("a");
+        GLYPH_1EM_WIDTH = paint.measureText("b");
+    }
+
     // list of family names to try when attempting to find a typeface with a given style
     private static final String[] FAMILIES =
             { (String) null, "monospace", "serif", "sans-serif", "cursive", "arial", "times" };
@@ -515,4 +528,68 @@
 
         assertTrue(Math.abs(widthFromRegular - widthFromBlack) > 1.0f);
     }
+
+    @Test
+    public void testTypefaceCreate_withExactWeight() {
+        // multiweight_family has following fonts.
+        // - a3em.ttf with weight = 100, style=normal configuration.
+        //   This font supports "a", "b", "c". The weight "a" is 3em, others are 1em.
+        // - b3em.ttf with weight = 400, style=normal configuration.
+        //   This font supports "a", "b", "c". The weight "b" is 3em, others are 1em.
+        // - c3em.ttf with weight = 700, style=normal configuration.
+        //   This font supports "a", "b", "c". The weight "c" is 3em, others are 1em.
+        final Typeface family = mContext.getResources().getFont(R.font.multiweight_family);
+        assertNotNull(family);
+
+        final Paint paint = new Paint();
+        // By default, the font which weight is 400 is selected.
+        paint.setTypeface(family);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+        // Draw with the font which weight is 100.
+        paint.setTypeface(Typeface.create(family, 100 /* weight */, false /* italic */));
+        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+        // Draw with the font which weight is 700.
+        paint.setTypeface(Typeface.create(family, 700 /* weight */, false /* italic */));
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0f);
+    }
+
+    @Test
+    public void testTypefaceCreate_withExactStyle() {
+        // multiweight_family has following fonts.
+        // - a3em.ttf with weight = 400, style=normal configuration.
+        //   This font supports "a", "b", "c". The weight "a" is 3em, others are 1em.
+        // - b3em.ttf with weight = 400, style=italic configuration.
+        //   This font supports "a", "b", "c". The weight "b" is 3em, others are 1em.
+        // - c3em.ttf with weight = 700, style=italic configuration.
+        //   This font supports "a", "b", "c". The weight "c" is 3em, others are 1em.
+        final Typeface family = mContext.getResources().getFont(R.font.multistyle_family);
+        assertNotNull(family);
+
+        final Paint paint = new Paint();
+        // By default, the normal style font which weight is 400 is selected.
+        paint.setTypeface(family);
+        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+        // Draw with the italic font.
+        paint.setTypeface(Typeface.create(family, 400 /* weight */, true /* italic */));
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+        // Draw with the italic font which weigth is 700.
+        paint.setTypeface(Typeface.create(family, 700 /* weight */, true /* italic */));
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0f);
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java b/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
index 75d7b7c..8968442 100644
--- a/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
@@ -23,26 +23,79 @@
 import java.util.GregorianCalendar;
 
 public class GeomagneticFieldTest extends AndroidTestCase {
-    // Chengdu: Latitude 30d 40' 12", Longitude 104d 3' 36"
-    private static final float LATITUDE_OF_CHENGDU = 30.67f;
-    private static final float LONGITUDE_OF_CHENGDU = 104.06f;
-    private static final float ALTITUDE_OF_CHENGDU = 500f;
-    private static final long TEST_TIME = new GregorianCalendar(2010, 5, 1).getTimeInMillis();
+    private static final float DECLINATION_THRESHOLD = 0.1f;
+    private static final float INCLINATION_THRESHOLD = 0.1f;
+    private static final float FIELD_STRENGTH_THRESHOLD = 100;
 
     @Presubmit
     public void testGeomagneticField() {
-        GeomagneticField geomagneticField = new GeomagneticField(LATITUDE_OF_CHENGDU,
-                LONGITUDE_OF_CHENGDU, ALTITUDE_OF_CHENGDU, TEST_TIME);
+        // Reference values calculated from NOAA online calculator for WMM 2015
+        // https://www.ngdc.noaa.gov/geomag-web/#igrfwmm
+        TestDataPoint testPoints[] = new TestDataPoint[] {
+            // Mountain View, CA, USA on 2017/1/1
+            new TestDataPoint(37.386f, -122.083f, 32, 2017, 1, 1,
+                    13.4589f, 60.9542f, 48168.0f),
+            // Chengdu, China on 2017/8/8
+            new TestDataPoint(30.658f, 103.935f, 500f, 2017, 8, 8,
+                    -1.9784f, 47.9723f, 50717.3f),
+            // Sao Paulo, Brazil on 2018/12/25
+            new TestDataPoint(-23.682f, -46.875f, 760f, 2018, 12, 25,
+                    -21.3130f, -37.9940f, 22832.3f),
+            // Boston, MA, USA on 2019/2/10
+            new TestDataPoint(42.313f, -71.127f, 43f, 2019, 2, 10,
+                    -14.5391f, 66.9693f, 51815.1f),
+            // Cape Town, South Africa on 2019/5/1
+            new TestDataPoint(-33.913f, 18.095f, 100f, 2019, 5, 1,
+                    -25.2454f, -65.8887f, 25369.2f),
+            // Sydney, Australia on 2020/1/1
+            new TestDataPoint(-33.847f, 150.791f, 19f, 2020, 1, 1,
+                    12.4469f, -64.3443f, 57087.9f)
+        };
 
-        // Reference values calculated from NOAA online calculator for WMM 2010,
-        // and cross-checked in Matlab. The expected deltas are proportional to the
-        // magnitude of each value.
-        assertEquals(-1.867f, geomagneticField.getDeclination(), 0.1f);
-        assertEquals(47.133f, geomagneticField.getInclination(), 1.0f);
-        assertEquals(50375.6f, geomagneticField.getFieldStrength(), 100.0f);
-        assertEquals(34269.3f, geomagneticField.getHorizontalStrength(), 100.0f);
-        assertEquals(34251.2f, geomagneticField.getX(), 100.0f);
-        assertEquals(-1113.2f, geomagneticField.getY(), 10.0f);
-        assertEquals(36923.1f, geomagneticField.getZ(), 100.0f);
+        for (TestDataPoint t : testPoints) {
+            GeomagneticField field =
+                    new GeomagneticField(t.latitude, t.longitude, t.altitude, t.epochTimeMillis);
+            assertEquals(t.declinationDegree,  field.getDeclination(), DECLINATION_THRESHOLD);
+            assertEquals(t.inclinationDegree,  field.getInclination(), INCLINATION_THRESHOLD);
+            assertEquals(t.fieldStrengthNanoTesla, field.getFieldStrength(),
+                    FIELD_STRENGTH_THRESHOLD);
+
+            float horizontalFieldStrengthNanoTesla = (float)(
+                    Math.cos(Math.toRadians(t.inclinationDegree)) * t.fieldStrengthNanoTesla);
+            assertEquals(horizontalFieldStrengthNanoTesla, field.getHorizontalStrength(),
+                    FIELD_STRENGTH_THRESHOLD);
+
+            float verticalFieldStrengthNanoTesla = (float)(
+                    Math.sin(Math.toRadians(t.inclinationDegree)) * t.fieldStrengthNanoTesla);
+            assertEquals(verticalFieldStrengthNanoTesla, field.getZ(), FIELD_STRENGTH_THRESHOLD);
+
+            float declinationDegree = (float)(
+                    Math.toDegrees(Math.atan2(field.getY(), field.getX())));
+            assertEquals(t.declinationDegree, declinationDegree, DECLINATION_THRESHOLD);
+            assertEquals(horizontalFieldStrengthNanoTesla,
+                    Math.sqrt(field.getX() * field.getX() + field.getY() * field.getY()),
+                    FIELD_STRENGTH_THRESHOLD);
+        }
+    }
+
+    private class TestDataPoint {
+        public final float latitude;
+        public final float longitude;
+        public final float altitude;
+        public final long epochTimeMillis;
+        public final float declinationDegree;
+        public final float inclinationDegree;
+        public final float fieldStrengthNanoTesla;
+
+        TestDataPoint(float lat, float lng, float alt, int year, int month, int day,
+                float dec, float inc, float strength) {
+            latitude = lat;
+            longitude = lng;
+            altitude = alt;
+            epochTimeMillis = new GregorianCalendar(year, month, day).getTimeInMillis();
+            declinationDegree = dec;
+            inclinationDegree = inc;
+            fieldStrengthNanoTesla = strength;
+        }
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/GlUtils.java b/tests/tests/hardware/src/android/hardware/cts/GlUtils.java
index 81628d4..bd5cecb 100644
--- a/tests/tests/hardware/src/android/hardware/cts/GlUtils.java
+++ b/tests/tests/hardware/src/android/hardware/cts/GlUtils.java
@@ -17,6 +17,7 @@
 package android.hardware.cts;
 
 import android.opengl.GLES20;
+import android.util.Pair;
 
 import java.util.Arrays;
 import java.util.regex.Matcher;
@@ -27,6 +28,10 @@
     }
 
     static int getMajorVersion() {
+        return getVersion().first;
+    }
+
+    static Pair<Integer, Integer> getVersion() {
         // Section 6.1.5 of the OpenGL ES specification indicates the GL version
         // string strictly follows this format:
         //
@@ -42,9 +47,10 @@
         Pattern pattern = Pattern.compile("OpenGL ES ([0-9]+)\\.([0-9]+)");
         Matcher matcher = pattern.matcher(version);
         if (matcher.find()) {
-            return Integer.parseInt(matcher.group(1));
+            return new Pair<>(
+                    Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)));
         }
-        return 2;
+        return new Pair<>(2, 0);
     }
 
     static String[] getExtensions() {
diff --git a/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java b/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
index 5ea845a..6276959 100644
--- a/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
@@ -24,6 +24,7 @@
 import android.opengl.EGLSurface;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -70,8 +71,10 @@
             }, 0);
             EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
 
-            sHasFloatBuffers = GlUtils.getMajorVersion() >= 3 ||
-                    GlUtils.hasExtensions("GL_OES_texture_half_float",
+            Pair<Integer, Integer> version = GlUtils.getVersion();
+            sHasFloatBuffers = (version.first >= 3 && version.second >= 2) ||
+                    GlUtils.hasExtensions(
+                            "GL_OES_texture_half_float",
                             "GL_OES_texture_half_float_linear");
 
             EGL14.eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index 748b756..77ac34b 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -77,9 +77,7 @@
 
 static bool not_accessible(const std::string& library, const std::string& err) {
   return err.find("dlopen failed: library \"" + library + "\"") == 0 &&
-         (err.find("is not accessible for the namespace \"classloader-namespace\"") != std::string::npos ||
-          err.find("is not accessible for the namespace \"sphal\"") != std::string::npos ||
-          err.find("is not accessible for the namespace \"(default)\"") != std::string::npos);
+         err.find("is not accessible for the namespace \"classloader-namespace\"") != std::string::npos;
 }
 
 static bool not_found(const std::string& library, const std::string& err) {
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 67c4e3a..a0a8536 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -62,6 +62,9 @@
 import android.test.AndroidTestCase;
 import android.util.ArraySet;
 
+import com.android.org.bouncycastle.asn1.x500.X500Name;
+import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+
 import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -70,6 +73,7 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.ProviderException;
+import java.security.PublicKey;
 import java.security.SignatureException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
@@ -422,7 +426,7 @@
 
         try {
             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
-            verifyCertificateSignatures(certificates);
+            verifyCertificateChain((X509Certificate[])certificates);
 
             X509Certificate attestationCert = (X509Certificate) certificates[0];
             Attestation attestation = new Attestation(attestationCert);
@@ -476,7 +480,7 @@
 
         try {
             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
-            verifyCertificateSignatures(certificates);
+            verifyCertificateChain((X509Certificate[])certificates);
 
             X509Certificate attestationCert = (X509Certificate) certificates[0];
             Attestation attestation = new Attestation(attestationCert);
@@ -767,8 +771,6 @@
         assertNotNull(rootOfTrust);
         assertNotNull(rootOfTrust.getVerifiedBootKey());
         assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32);
-        assertTrue(rootOfTrust.isDeviceLocked());
-        assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
     }
 
     private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes,
@@ -878,12 +880,34 @@
         keyPairGenerator.generateKeyPair();
     }
 
-    private void verifyCertificateSignatures(Certificate[] certChain)
+    private void verifyCertificateChain(X509Certificate[] certChain)
             throws GeneralSecurityException {
         assertNotNull(certChain);
         for (int i = 1; i < certChain.length; ++i) {
             try {
-                certChain[i - 1].verify(certChain[i].getPublicKey());
+                PublicKey pubKey = certChain[i].getPublicKey();
+                certChain[i - 1].verify(pubKey);
+                if (i == certChain.length - 1) {
+                    // Last cert should be self-signed.
+                    certChain[i].verify(pubKey);
+                }
+
+                // Check that issuer in the signed cert matches subject in the signing cert.
+                X500Name signingCertSubject =
+                    new JcaX509CertificateHolder(certChain[i]).getSubject();
+                X500Name signedCertIssuer =
+                    new JcaX509CertificateHolder(certChain[i - 1]).getIssuer();
+                // Use .toASN1Object().equals() rather than .equals() because .equals() is case
+                // insensitive, and we want to verify an exact match.
+                assertTrue(
+                        signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object()));
+
+                if (i == 1) {
+                    // First cert should have subject "CN=Android Keystore Key".
+                    X500Name signedCertSubject =
+                            new JcaX509CertificateHolder(certChain[i - 1]).getSubject();
+                    assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key"));
+                }
             } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException
                     | NoSuchProviderException | SignatureException e) {
                 throw new GeneralSecurityException("Failed to verify certificate "
diff --git a/tests/tests/media/AndroidTest.xml b/tests/tests/media/AndroidTest.xml
index d370d38..03d4770 100644
--- a/tests/tests/media/AndroidTest.xml
+++ b/tests/tests/media/AndroidTest.xml
@@ -26,6 +26,8 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.cts" />
+        <!-- setup can be expensive so limit the number of shards -->
+        <option name="ajur-max-shard" value="5" />
         <!-- test-timeout unit is ms, value = 30 min -->
         <option name="test-timeout" value="1800000" />
         <option name="runtime-hint" value="4h" />
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
index 6cf9a89..28c528c 100644
--- a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -64,6 +64,8 @@
     0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b
 };
 
+// The test content is not packaged with clearkey UUID,
+// we have to use a canned clearkey pssh for the test.
 static const uint8_t kClearkeyPssh[] = {
     // BMFF box header (4 bytes size + 'pssh')
     0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index fd8c3b1..c401c75 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -300,6 +300,24 @@
                 mSubscriptionCallback.mLastOptions.getInt(MediaBrowser.EXTRA_PAGE_SIZE));
     }
 
+    public void testSubscriptionCallbackNotCalledAfterDisconnect() {
+        createMediaBrowser(TEST_BROWSER_SERVICE);
+        connectMediaBrowserService();
+        mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+        mMediaBrowser.disconnect();
+        resetCallbacks();
+        StubMediaBrowserService.sInstance.notifyChildrenChanged(
+                StubMediaBrowserService.MEDIA_ID_ROOT);
+        try {
+            Thread.sleep(SLEEP_MS);
+        } catch (InterruptedException e) {
+            fail("Unexpected InterruptedException occurred.");
+        }
+        assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
+        assertEquals(0, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
+        assertNull(mSubscriptionCallback.mLastParentId);
+    }
+
     public void testUnsubscribeForMultipleSubscriptions() {
         createMediaBrowser(TEST_BROWSER_SERVICE);
         connectMediaBrowserService();
@@ -436,6 +454,21 @@
         assertEquals(StubMediaBrowserService.MEDIA_ID_INVALID, mItemCallback.mLastErrorId);
     }
 
+    public void testItemCallbackNotCalledAfterDisconnect() {
+        createMediaBrowser(TEST_BROWSER_SERVICE);
+        connectMediaBrowserService();
+        mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+        mMediaBrowser.disconnect();
+        resetCallbacks();
+        try {
+            Thread.sleep(SLEEP_MS);
+        } catch (InterruptedException e) {
+            fail("Unexpected InterruptedException occurred.");
+        }
+        assertNull(mItemCallback.mLastMediaItem);
+        assertNull(mItemCallback.mLastErrorId);
+    }
+
     private void createMediaBrowser(final ComponentName component) {
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
diff --git a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
index 2375d46..f6d5e83 100644
--- a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
@@ -153,6 +153,7 @@
         try {
             testGetPropertyStringNative(uuidByteArray(CLEARKEY_SCHEME_UUID),
                     "unknown-property", value);
+            fail("Should have thrown an exception");
         } catch (RuntimeException e) {
             Log.e(TAG, "testUnknownPropertyString error = '" + e.getMessage() + "'");
             assertThat(e.getMessage(), containsString("get property string returns"));
diff --git a/tests/tests/nativemedia/aaudio/Android.mk b/tests/tests/nativemedia/aaudio/Android.mk
index 66acd71..2017eba 100644
--- a/tests/tests/nativemedia/aaudio/Android.mk
+++ b/tests/tests/nativemedia/aaudio/Android.mk
@@ -1,4 +1,4 @@
-# Copyright 2017 The Android Open Source Project
+# Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,39 +12,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Build the unit tests.
-
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CtsNativeMediaAAudioTestCases
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+
+LOCAL_PACKAGE_NAME := CtsNativeMediaAAudioTestCases
+
+# Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
-LOCAL_SRC_FILES := \
-    src/test_aaudio.cpp \
-    src/test_aaudio_misc.cpp \
-    src/test_aaudio_callback.cpp \
-    src/test_aaudio_stream_builder.cpp \
-    src/utils.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    libaaudio \
-    liblog \
-
-LOCAL_STATIC_LIBRARIES := \
-    libgtest_ndk_c++ \
-
-LOCAL_CTS_TEST_PACKAGE := android.nativemedia.aaudio
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-LOCAL_CFLAGS := -Werror -Wall
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner nativetesthelper
+
+LOCAL_JNI_SHARED_LIBRARIES := libnativeaaudiotest
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_SDK_VERSION := current
-LOCAL_NDK_STL_VARIANT := c++_static
 
-include $(BUILD_CTS_EXECUTABLE)
+include $(BUILD_CTS_PACKAGE)
+
+# Include the associated library's makefile.
+include $(LOCAL_PATH)/jni/Android.mk
diff --git a/tests/tests/nativemedia/aaudio/AndroidManifest.xml b/tests/tests/nativemedia/aaudio/AndroidManifest.xml
new file mode 100644
index 0000000..97bf5f9
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.nativemedia.aaudio">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.nativemedia.aaudio"
+                     android:label="CTS tests of native AAudio API">
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/nativemedia/aaudio/AndroidTest.xml b/tests/tests/nativemedia/aaudio/AndroidTest.xml
index 7030d0c..b796ea6 100644
--- a/tests/tests/nativemedia/aaudio/AndroidTest.xml
+++ b/tests/tests/nativemedia/aaudio/AndroidTest.xml
@@ -15,16 +15,14 @@
 -->
 <configuration description="Config for CTS Native Media AAudio test cases">
     <option name="config-descriptor:metadata" key="component" value="media" />
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="cleanup" value="true" />
-        <option name="push" value="CtsNativeMediaAAudioTestCases->/data/local/tmp/CtsNativeMediaAAudioTestCases" />
-        <option name="append-bitness" value="true" />
+    <option name="test-suite-tag" value="cts" />
+    <option name="not-shardable" value="true" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsNativeMediaAAudioTestCases.apk" />
     </target_preparer>
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="CtsNativeMediaAAudioTestCases" />
-        <option name="runtime-hint" value="2m" />
-        <!-- test-timeout unit is ms, value = 2 min -->
-        <option name="native-test-timeout" value="120000" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.nativemedia.aaudio" />
+        <option name="runtime-hint" value="2m0s" />
     </test>
 </configuration>
diff --git a/tests/tests/nativemedia/aaudio/jni/Android.mk b/tests/tests/nativemedia/aaudio/jni/Android.mk
new file mode 100644
index 0000000..8ef7aac
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/jni/Android.mk
@@ -0,0 +1,41 @@
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build the unit tests.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libnativeaaudiotest
+LOCAL_MULTILIB := both
+
+LOCAL_SRC_FILES := \
+    test_aaudio.cpp \
+    test_aaudio_misc.cpp \
+    test_aaudio_callback.cpp \
+    test_aaudio_stream_builder.cpp \
+    utils.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libaaudio \
+    liblog
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libnativetesthelper_jni
+
+LOCAL_CFLAGS := -Werror -Wall
+
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.h b/tests/tests/nativemedia/aaudio/jni/test_aaudio.h
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio.h
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio.h
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio_callback.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio_callback.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio_misc.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio_misc.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_stream_builder.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio_stream_builder.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio_stream_builder.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio_stream_builder.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/utils.cpp b/tests/tests/nativemedia/aaudio/jni/utils.cpp
similarity index 92%
rename from tests/tests/nativemedia/aaudio/src/utils.cpp
rename to tests/tests/nativemedia/aaudio/jni/utils.cpp
index 8b9f60d..d1a3115 100644
--- a/tests/tests/nativemedia/aaudio/src/utils.cpp
+++ b/tests/tests/nativemedia/aaudio/jni/utils.cpp
@@ -161,22 +161,6 @@
         : StreamBuilderHelper{AAUDIO_DIRECTION_INPUT,
             48000, 1, AAUDIO_FORMAT_PCM_I16, requestedSharingMode, requestedPerfMode} {}
 
-// Native apps don't have permissions, thus recording can
-// only be tested when running as root.
-static bool canTestRecording() {
-    static const bool runningAsRoot = getuid() == 0;
-    return runningAsRoot;
-}
-
-void InputStreamBuilderHelper::createAndVerifyStream(bool *success) {
-    if (!canTestRecording()) {
-        __android_log_write(ANDROID_LOG_WARN, LOG_TAG, "No permissions to run recording tests");
-        *success = false;
-    } else {
-        StreamBuilderHelper::createAndVerifyStream(success);
-    }
-}
-
 
 OutputStreamBuilderHelper::OutputStreamBuilderHelper(
         aaudio_sharing_mode_t requestedSharingMode, aaudio_performance_mode_t requestedPerfMode)
diff --git a/tests/tests/nativemedia/aaudio/src/utils.h b/tests/tests/nativemedia/aaudio/jni/utils.h
similarity index 98%
rename from tests/tests/nativemedia/aaudio/src/utils.h
rename to tests/tests/nativemedia/aaudio/jni/utils.h
index fbb3e76..77bbc52 100644
--- a/tests/tests/nativemedia/aaudio/src/utils.h
+++ b/tests/tests/nativemedia/aaudio/jni/utils.h
@@ -81,7 +81,6 @@
     InputStreamBuilderHelper(
             aaudio_sharing_mode_t requestedSharingMode,
             aaudio_performance_mode_t requestedPerfMode);
-    void createAndVerifyStream(bool *success);
 };
 
 class OutputStreamBuilderHelper : public StreamBuilderHelper {
diff --git a/tests/tests/nativemedia/aaudio/src/android/nativemedia/aaudio/AAudioTests.java b/tests/tests/nativemedia/aaudio/src/android/nativemedia/aaudio/AAudioTests.java
new file mode 100644
index 0000000..afb2db4
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/android/nativemedia/aaudio/AAudioTests.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nativemedia.aaudio;
+
+import org.junit.runner.RunWith;
+import com.android.gtestrunner.GtestRunner;
+import com.android.gtestrunner.TargetLibrary;
+
+@RunWith(GtestRunner.class)
+@TargetLibrary("nativeaaudiotest")
+public class AAudioTests {}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index cd6dbb2..1396a1c 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,8 +16,11 @@
 
 package android.net.cts;
 
+import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
 import android.app.PendingIntent;
@@ -29,6 +32,7 @@
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkConfig;
@@ -49,14 +53,23 @@
 import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.Inet6Address;
+import java.net.InetAddress;
 import java.net.Socket;
 import java.net.InetSocketAddress;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import libcore.io.Streams;
 
 public class ConnectivityManagerTest extends AndroidTestCase {
 
@@ -106,6 +119,8 @@
     private final HashMap<Integer, NetworkConfig> mNetworks =
             new HashMap<Integer, NetworkConfig>();
     boolean mWifiConnectAttempted;
+    private TestNetworkCallback mCellNetworkCallback;
+
 
     @Override
     protected void setUp() throws Exception {
@@ -138,6 +153,10 @@
         if (mWifiConnectAttempted) {
             disconnectFromWifi(null);
         }
+        if (cellConnectAttempted()) {
+            disconnectFromCell();
+        }
+        super.tearDown();
     }
 
     /**
@@ -244,6 +263,95 @@
         }
     }
 
+    /**
+     * Tests that connections can be opened on WiFi and cellphone networks,
+     * and that they are made from different IP addresses.
+     */
+    public void testOpenConnection() throws Exception {
+        boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
+                && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
+        if (!canRunTest) {
+            Log.i(TAG,"testOpenConnection cannot execute unless device supports both WiFi "
+                    + "and a cellular connection");
+            return;
+        }
+
+        Network wifiNetwork = connectToWifi();
+        Network cellNetwork = connectToCell();
+        // This server returns the requestor's IP address as the response body.
+        URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
+        String wifiAddressString = httpGet(wifiNetwork, url);
+        String cellAddressString = httpGet(cellNetwork, url);
+
+        assertFalse(String.format("Same address '%s' on two different networks (%s, %s)",
+                wifiAddressString, wifiNetwork, cellNetwork),
+                wifiAddressString.equals(cellAddressString));
+
+        // Sanity check that the IP addresses that the requests appeared to come from
+        // are actually on the respective networks.
+        assertOnNetwork(wifiAddressString, wifiNetwork);
+        assertOnNetwork(cellAddressString, cellNetwork);
+
+        assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
+    }
+
+    private Network connectToCell() throws InterruptedException {
+        if (cellConnectAttempted()) {
+            throw new IllegalStateException("Already connected");
+        }
+        NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+        mCellNetworkCallback = new TestNetworkCallback();
+        mCm.requestNetwork(cellRequest, mCellNetworkCallback);
+        final Network cellNetwork = mCellNetworkCallback.waitForAvailable();
+        assertNotNull("Cell network not available within timeout", cellNetwork);
+        return cellNetwork;
+    }
+
+    private boolean cellConnectAttempted() {
+        return mCellNetworkCallback != null;
+    }
+
+    private void disconnectFromCell() {
+        if (!cellConnectAttempted()) {
+            throw new IllegalStateException("Cell connection not attempted");
+        }
+        mCm.unregisterNetworkCallback(mCellNetworkCallback);
+        mCellNetworkCallback = null;
+    }
+
+    /**
+     * Performs a HTTP GET to the specified URL on the specified Network, and returns
+     * the response body decoded as UTF-8.
+     */
+    private static String httpGet(Network network, URL httpUrl) throws IOException {
+        HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl);
+        try {
+            InputStream inputStream = connection.getInputStream();
+            return Streams.readFully(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+        } finally {
+            connection.disconnect();
+        }
+    }
+
+    private void assertOnNetwork(String adressString, Network network) throws UnknownHostException {
+        InetAddress address = InetAddress.getByName(adressString);
+        LinkProperties linkProperties = mCm.getLinkProperties(network);
+        // To make sure that the request went out on the right network, check that
+        // the IP address seen by the server is assigned to the expected network.
+        // We can only do this for IPv6 addresses, because in IPv4 we will likely
+        // have a private IPv4 address, and that won't match what the server sees.
+        if (address instanceof Inet6Address) {
+            assertContains(linkProperties.getAddresses(), address);
+        }
+    }
+
+    private static<T> void assertContains(Collection<T> collection, T element) {
+        assertTrue(element + " not found in " + collection, collection.contains(element));
+    }
+
     private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
         try {
             mCm.startUsingNetworkFeature(networkType, feature);
@@ -323,7 +431,7 @@
      * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?).
      */
     public void testRegisterNetworkCallback() {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
             return;
         }
@@ -363,7 +471,7 @@
      * of a {@code NetworkCallback}.
      */
     public void testRegisterNetworkCallback_withPendingIntent() {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
             return;
         }
@@ -457,7 +565,7 @@
      * Tests reporting of connectivity changed.
      */
     public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi");
             return;
         }
@@ -474,7 +582,7 @@
     }
 
     public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi");
             return;
         }
@@ -494,7 +602,7 @@
 
     public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent()
             throws InterruptedException {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi");
             return;
         }
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
index 4c68423..b45bfe0 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
@@ -23,9 +23,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
     ctstestserver \
-    org.apache.http.legacy \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src common)
 
 LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficFalseTestCases
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
index 49385f8..d4ce39a 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
@@ -22,6 +22,7 @@
   <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
   <application>
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
index 584afd2..89195cd 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
@@ -23,9 +23,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
     ctstestserver \
-    org.apache.http.legacy \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src common)
 
 LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficTrueTestCases
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
index be698f2..fe31e80 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
@@ -22,6 +22,7 @@
   <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
   <application>
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
index 9a613e7..bad2cbc 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
@@ -23,9 +23,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
     ctstestserver \
-    org.apache.http.legacy \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src common)
 
 LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficUnspecifiedTestCases
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
index 7bd8742..c6b65c0 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
@@ -22,6 +22,7 @@
   <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
   <application>
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
index 10018ce..4af2de7 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
@@ -20,7 +20,9 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
@@ -31,4 +33,4 @@
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml
index 9356074..972052e 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml
@@ -20,6 +20,7 @@
         package="android.security.net.config.cts.CtsNetSecConfigAttributeTestCases">
   <application android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
index 161dbd3..95e14ef 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
@@ -20,7 +20,9 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
@@ -31,4 +33,4 @@
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml
index 565f23a..3e5fe25 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml
@@ -20,6 +20,7 @@
         package="android.security.net.config.cts.CtsNetSecConfigBasicDomainConfigTestCases">
   <application android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
index 927374c..278d634 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
@@ -20,7 +20,9 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml
index b387ffa..8ee5482 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml
@@ -20,6 +20,7 @@
         package="android.security.net.config.cts.CtsNetSecConfigCleartextTrafficTestCases">
   <application android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
index aa0eefd..fd5f419 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
@@ -20,7 +20,9 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
@@ -31,4 +33,4 @@
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml
index 3f15f81..28bba5b 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml
@@ -21,6 +21,7 @@
   <application android:debuggable="false"
                android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
index be9174e..d808928 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
@@ -20,7 +20,9 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml
index 6d98702..b667271 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml
@@ -21,6 +21,7 @@
   <application android:debuggable="true"
                android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
index 84e72b0..54727c6 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
@@ -22,10 +22,11 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
-    org.apache.http.legacy \
     android-support-test \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
 
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml
index e18ff4d..cc67cca 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml
@@ -20,6 +20,7 @@
         package="android.security.net.config.cts.CtsNetSecConfigDownloadManagerTestCases">
   <application android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
index 4764cab..3d66c53 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
@@ -20,7 +20,9 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml
index b3b32b5..bf6e369 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml
@@ -20,6 +20,7 @@
         package="android.security.net.config.cts.CtsNetSecConfigInvalidPinTestCases">
   <application android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
index 5448f34..e96ae6a 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
@@ -20,7 +20,9 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml
index 1790150..75247d3 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml
@@ -20,6 +20,7 @@
         package="android.security.net.config.cts.CtsNetSecConfigNestedDomainConfigTestCases">
   <application android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
index 924f393..4e7efdeb 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
@@ -22,10 +22,11 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
-    org.apache.http.legacy \
     android-support-test \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
 
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml
index 46787160..4884458 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml
@@ -20,6 +20,7 @@
         package="android.security.net.config.cts.CtsNetSecConfigResourcesSrcTestCases">
   <application android:networkSecurityConfig="@xml/network_security_config">
       <uses-library android:name="android.test.runner"/>
+      <uses-library android:name="org.apache.http.legacy" />
   </application>
 
   <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
index 4225de0..24b0f6a 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -191,7 +191,7 @@
             "EGL_KHR_wait_sync",
         };
 
-        for (int i = 0; i < requiredList.length; ++i) {
+        for (int i = 0; i < requiredEglList.length; ++i) {
             assertTrue("Required EGL extension for VR high-performance is missing: " +
                 requiredEglList[i], hasExtension(extensions, requiredEglList[i]));
         }
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index 8104cab..52c184f 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1 +1 @@
-8.1.0
+P
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index a820ac0..676465e 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -617,6 +617,38 @@
         looperThread.join();
     }
 
+    public void testOpenProxyFileDescriptor_largeFile() throws Exception {
+        final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() {
+            @Override
+            public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+                for (int i = 0; i < size; i++) {
+                    data[i] = 'L';
+                }
+                return size;
+            }
+
+            @Override
+            public long onGetSize() throws ErrnoException {
+                return 8L * 1024L * 1024L * 1024L;  // 8GB
+            }
+
+            @Override
+            public void onRelease() {}
+        };
+        final byte[] bytes = new byte[128];
+        try (final ParcelFileDescriptor fd = mStorageManager.openProxyFileDescriptor(
+                ParcelFileDescriptor.MODE_READ_ONLY, callback)) {
+            assertEquals(8L * 1024L * 1024L * 1024L, fd.getStatSize());
+
+            final int readBytes = Os.pread(
+                    fd.getFileDescriptor(), bytes, 0, bytes.length, fd.getStatSize() - 64L);
+            assertEquals(64, readBytes);
+            for (int i = 0; i < 64; i++) {
+                assertEquals('L', bytes[i]);
+            }
+        }
+    }
+
     private void assertStorageVolumesEquals(StorageVolume volume, StorageVolume clone)
             throws Exception {
         // Asserts equals() method.
diff --git a/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java b/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java
index 921f5f1..06e858e 100644
--- a/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java
+++ b/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java
@@ -41,7 +41,6 @@
     private PackageManager mPm;
     private String mPackageName;
     private UiDevice mUiDevice;
-    private boolean mHasFeature;
 
     @Before
     public void setUp() throws Exception {
@@ -49,7 +48,6 @@
         mPm = mContext.getPackageManager();
         mPackageName = mContext.getPackageName();
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        mHasFeature = !mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
     }
 
     private void setAppOpsMode(String mode) throws IOException {
@@ -86,9 +84,6 @@
 
     @Test
     public void testManageUnknownSourcesExists() {
-        if (!mHasFeature) {
-            return;
-        }
         Intent manageUnknownSources = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
         ResolveInfo info = mPm.resolveActivity(manageUnknownSources, 0);
         Assert.assertNotNull("No activity found for " + manageUnknownSources.getAction(), info);
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index ebcd41e..f77c9b3 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -510,6 +510,23 @@
         mCreateActivityCallCounter.reset();
     }
 
+    /**
+     * Wait until the message is shown that indicates that a printer is unavailable.
+     *
+     * @throws Exception If anything was unexpected.
+     */
+    protected void waitForPrinterUnavailable() throws Exception {
+        final String printerUnavailableMessage =
+                getPrintSpoolerString("print_error_printer_unavailable");
+
+        UiObject message = getUiDevice().findObject(new UiSelector().resourceId(
+                "com.android.printspooler:id/message"));
+        if (!message.getText().equals(printerUnavailableMessage)) {
+            throw new Exception("Wrong message: " + message.getText() + " instead of "
+                    + printerUnavailableMessage);
+        }
+    }
+
     void selectPrinter(String printerName) throws UiObjectNotFoundException, IOException {
         try {
             long delay = 1;
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java b/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
index c3e6e96..486d6e4 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
@@ -42,6 +42,12 @@
         }
 
         BasePrintTest.onActivityCreateCalled(mTestId, this);
+
+        if (savedInstanceState != null) {
+            Log.d(LOG_TAG,
+                    "We cannot deal with lifecycle. Hence finishing " + this + " for " + mTestId);
+            finish();
+        }
     }
 
     @Override
diff --git a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
index 9b277e9..d391bd2 100644
--- a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
@@ -16,6 +16,8 @@
 
 package android.print.cts;
 
+import static android.print.cts.Utils.runOnMainThread;
+
 import android.os.ParcelFileDescriptor;
 import android.print.PageRange;
 import android.print.PrintAttributes;
@@ -34,9 +36,8 @@
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
 import android.print.cts.services.SecondPrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
 import android.util.Log;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -47,8 +48,6 @@
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
-import static android.print.cts.Utils.runOnMainThread;
-
 /**
  * This test verifies changes to the printer capabilities are applied correctly.
  */
@@ -154,23 +153,6 @@
                         PrinterInfo.STATUS_UNAVAILABLE)));
     }
 
-    /**
-     * Wait until the message is shown that indicates that a printer is unavilable.
-     *
-     * @throws Exception If anything was unexpected.
-     */
-    private void waitForPrinterUnavailable() throws Exception {
-        final String PRINTER_UNAVAILABLE_MSG =
-                getPrintSpoolerString("print_error_printer_unavailable");
-
-        UiObject message = getUiDevice().findObject(new UiSelector().resourceId(
-                "com.android.printspooler:id/message"));
-        if (!message.getText().equals(PRINTER_UNAVAILABLE_MSG)) {
-            throw new Exception("Wrong message: " + message.getText() + " instead of " +
-                    PRINTER_UNAVAILABLE_MSG);
-        }
-    }
-
     @Before
     public void setUpPrinting() throws Exception {
         // Create the mSession[0] callbacks that we will be checking.
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index 499d21e..c90b9e6 100644
--- a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -16,8 +16,13 @@
 
 package android.print.cts;
 
-import static android.print.cts.Utils.*;
-import static org.junit.Assert.*;
+import static android.print.cts.Utils.eventually;
+import static android.print.cts.Utils.runOnMainThread;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.inOrder;
 
 import android.print.PrintAttributes;
@@ -35,8 +40,11 @@
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.printservice.PrintJob;
 import android.printservice.PrinterDiscoverySession;
-
+import android.support.annotation.NonNull;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -53,10 +61,7 @@
  */
 @RunWith(AndroidJUnit4.class)
 public class PrinterDiscoverySessionLifecycleTest extends BasePrintTest {
-    private static final String FIRST_PRINTER_NAME = "First printer";
-    private static final String SECOND_PRINTER_NAME = "Second printer";
-
-    private static final String FIRST_PRINTER_LOCAL_ID= "first_printer";
+    private static final String FIRST_PRINTER_LOCAL_ID = "first_printer";
     private static final String SECOND_PRINTER_LOCAL_ID = "second_printer";
 
     private static StubbablePrinterDiscoverySession sSession;
@@ -66,6 +71,172 @@
         clearPrintSpoolerData();
     }
 
+    /**
+     * Add a printer to {@#sSession}.
+     *
+     * @param localId The id of the printer to add
+     * @param hasCapabilities If the printer has capabilities
+     */
+    private void addPrinter(@NonNull String localId, boolean hasCapabilities) {
+        // Add the first printer.
+        PrinterId firstPrinterId = sSession.getService().generatePrinterId(
+                localId);
+
+        PrinterInfo.Builder printer = new PrinterInfo.Builder(firstPrinterId,
+                localId, PrinterInfo.STATUS_IDLE);
+
+        if (hasCapabilities) {
+            printer.setCapabilities(new PrinterCapabilitiesInfo.Builder(firstPrinterId)
+                    .setMinMargins(new Margins(200, 200, 200, 200))
+                    .addMediaSize(MediaSize.ISO_A0, true)
+                    .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                            PrintAttributes.COLOR_MODE_COLOR)
+                    .build());
+        }
+
+        sSession.addPrinters(Collections.singletonList(printer.build()));
+    }
+
+    /**
+     * Make {@code localPrinterId} the default printer. This requires a full print workflow.
+     *
+     * As a side-effect also approved the print service.
+     *
+     * @param localPrinterId The printer to make default
+     */
+    private void makeDefaultPrinter(String localPrinterId) throws Throwable {
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+        print(adapter);
+        waitForWriteAdapterCallback(1);
+
+        runOnMainThread(() -> addPrinter(localPrinterId, true));
+        selectPrinter(localPrinterId);
+        waitForWriteAdapterCallback(2);
+
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+        resetCounters();
+    }
+
+    /**
+     * Select a printer in the all printers activity
+     *
+     * @param printerName The name of the printer to select
+     */
+    private void selectInAllPrintersActivity(@NonNull String printerName) throws Exception {
+        while (true) {
+            UiObject printerItem = getUiDevice().findObject(
+                    new UiSelector().text(printerName));
+
+            if (printerItem.isEnabled()) {
+                printerItem.click();
+                break;
+            } else {
+                Thread.sleep(100);
+            }
+        }
+    }
+
+    @Test
+    public void defaultPrinterBecomesAvailableWhileInBackground() throws Throwable {
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    sSession =
+                            ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
+
+                    onPrinterDiscoverySessionCreateCalled();
+                    return null;
+                }, null, null, null, null, null, invocation -> {
+                    onPrinterDiscoverySessionDestroyCalled();
+                    return null;
+                });
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                invocation -> firstSessionCallbacks, null, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        makeDefaultPrinter(FIRST_PRINTER_LOCAL_ID);
+
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+        print(adapter);
+        waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+        waitForPrinterUnavailable();
+
+        selectPrinter("All printers…");
+        // Let all printers activity start
+        Thread.sleep(500);
+
+        // Add printer
+        runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, true));
+
+        // Select printer once available (this returns to main print activity)
+        selectInAllPrintersActivity(FIRST_PRINTER_LOCAL_ID);
+
+        // Wait for preview to load and finish print
+        waitForWriteAdapterCallback(1);
+        clickPrintButton();
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    @Test
+    public void defaultPrinterBecomesUsableWhileInBackground() throws Throwable {
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    sSession =
+                            ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
+
+                    onPrinterDiscoverySessionCreateCalled();
+                    return null;
+                }, null, null, null, null, null, invocation -> {
+                    onPrinterDiscoverySessionDestroyCalled();
+                    return null;
+                });
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                invocation -> firstSessionCallbacks, null, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        makeDefaultPrinter(FIRST_PRINTER_LOCAL_ID);
+
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+        print(adapter);
+        waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+        // Add printer but do not enable it (capabilities == null)
+        runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, false));
+        waitForPrinterUnavailable();
+
+        selectPrinter("All printers…");
+        // Let all printers activity start
+        Thread.sleep(500);
+
+        // Enable printer
+        runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, true));
+
+        // Select printer once available (this returns to main print activity)
+        selectInAllPrintersActivity(FIRST_PRINTER_LOCAL_ID);
+
+        // Wait for preview to load and finish print
+        waitForWriteAdapterCallback(1);
+        clickPrintButton();
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
     @Test
     public void normalLifecycle() throws Throwable {
         // Create the session callbacks that we will be checking.
@@ -99,7 +270,7 @@
         runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
 
         // Select the first printer.
-        selectPrinter(FIRST_PRINTER_NAME);
+        selectPrinter(FIRST_PRINTER_LOCAL_ID);
 
         eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
                 sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -111,7 +282,7 @@
 
         // Select the second printer (same capabilities as the other
         // one so no layout should happen).
-        selectPrinter(SECOND_PRINTER_NAME);
+        selectPrinter(SECOND_PRINTER_LOCAL_ID);
 
         eventually(() -> runOnMainThread(() -> assertEquals(SECOND_PRINTER_LOCAL_ID,
                 sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -205,7 +376,7 @@
         runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
 
         // Select the first printer.
-        selectPrinter(FIRST_PRINTER_NAME);
+        selectPrinter(FIRST_PRINTER_LOCAL_ID);
 
         eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
                 sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -295,7 +466,7 @@
         runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
 
         // Select the first printer.
-        selectPrinter(FIRST_PRINTER_NAME);
+        selectPrinter(FIRST_PRINTER_LOCAL_ID);
 
         eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
                 sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -491,27 +662,9 @@
 
             assertTrue(sSession.isPrinterDiscoveryStarted());
 
-            if (sSession.getPrinters().isEmpty()) {
-                List<PrinterInfo> printers = new ArrayList<>();
+            addPrinter(FIRST_PRINTER_LOCAL_ID, false);
+            addPrinter(SECOND_PRINTER_LOCAL_ID, false);
 
-                // Add the first printer.
-                PrinterId firstPrinterId = sSession.getService().generatePrinterId(
-                        FIRST_PRINTER_LOCAL_ID);
-                PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
-                        FIRST_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
-                    .build();
-                printers.add(firstPrinter);
-
-                // Add the first printer.
-                PrinterId secondPrinterId = sSession.getService().generatePrinterId(
-                        SECOND_PRINTER_LOCAL_ID);
-                PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
-                        SECOND_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
-                    .build();
-                printers.add(secondPrinter);
-
-                sSession.addPrinters(printers);
-            }
             return null;
         }, invocation -> {
             assertFalse(sSession.isPrinterDiscoveryStarted());
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
index 3b38aba..c408d92 100644
--- a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
@@ -92,6 +92,7 @@
         // Try it in the provided name
         try {
             ProtoOutputStream.checkFieldId(42 | goodCount | badType, goodCount | fieldType);
+            fail("Should have thrown an exception.");
         } catch (IllegalArgumentException ex) {
             assertEquals("writeRepeated" + string
                         + " called for field 42 which should be used"
@@ -102,6 +103,7 @@
         // Try it in the expected name
         try {
             ProtoOutputStream.checkFieldId(43 | goodCount | fieldType, goodCount | badType);
+            fail("Should have thrown an exception.");
         } catch (IllegalArgumentException ex) {
             assertEquals("writeRepeated" + badTypeString
                         + " called for field 43 which should be used"
@@ -126,6 +128,7 @@
         // Try it in the provided name
         try {
             ProtoOutputStream.checkFieldId(44 | badCount | goodType, fieldCount | goodType);
+            fail("Should have thrown an exception.");
         } catch (IllegalArgumentException ex) {
             assertEquals("write" + string
                     + "Fixed32 called for field 44 which should be used"
@@ -136,6 +139,7 @@
         // Try it in the expected name
         try {
             ProtoOutputStream.checkFieldId(45 | fieldCount | goodType, badCount | goodType);
+            fail("Should have thrown an exception.");
         } catch (IllegalArgumentException ex) {
             String extraString = "";
             if (fieldCount == ProtoOutputStream.FIELD_COUNT_PACKED) {
@@ -151,7 +155,7 @@
     /**
      * Validate one call to checkFieldId that is expected to throw.
      */
-    public void assertCheckFieldIdThrows(long fieldId, long expectedFlags) 
+    public void assertCheckFieldIdThrows(long fieldId, long expectedFlags)
             throws Exception {
         try {
             ProtoOutputStream.checkFieldId(fieldId, expectedFlags);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java b/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
index 9b355b0..ab326ff 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
@@ -37,14 +37,14 @@
     /**
      * Test the orignal refocus code
      */
-    public void testOriginalRefocus() {
+    public void testOriginalRefocus() throws IOException {
         refocus(RenderScriptTask.script.f32, 95);
     }
 
     /**
      * Test the new refocus code
      */
-    public void testNewRefocus() {
+    public void testNewRefocus() throws IOException {
         // The new implementation may run on a GPU using relaxed floating point
         // mathematics. Hence more relaxed precision requirement.
         refocus(RenderScriptTask.script.d1new, 45);
@@ -54,7 +54,7 @@
      * Test a refocus operator against the refocus_reference image
      * @param impl version of refocus to run
      */
-    private void refocus(RenderScriptTask.script impl, double minimumPSNR) {
+    private void refocus(RenderScriptTask.script impl, double minimumPSNR) throws IOException {
         Context ctx = getContext();
 
         RenderScript rs = RenderScript.create(ctx);
@@ -63,27 +63,26 @@
             current_rgbz = new RGBZ(getResourceRef(R.drawable.test_image),
                                     getResourceRef(R.drawable.test_depthmap),
                                     ctx.getContentResolver(), ctx);
-        } catch (IOException e) {
-            e.printStackTrace();
-            assertNull(e);
+            DepthOfFieldOptions current_depth_options = new DepthOfFieldOptions(current_rgbz);
+            RsTaskParams rsTaskParam = new RsTaskParams(rs, current_depth_options);
+
+            RenderScriptTask renderScriptTask = new RenderScriptTask(rs, impl);
+            Bitmap outputImage = renderScriptTask.applyRefocusFilter(rsTaskParam.mOptions);
+
+            Bitmap expectedImage = BitmapFactory.decodeResource(ctx.getResources(),
+                    R.drawable.expected_output);
+
+            double psnr = ImageCompare.psnr(outputImage, expectedImage);
+            android.util.Log.i("RefocusTest", "psnr = " + String.format("%.02f", psnr));
+            if (psnr < minimumPSNR) {
+                MediaStoreSaver.savePNG(outputImage, "refocus", "refocus_output" , ctx);
+                assertTrue("Required minimum psnr = " + String.format("%.02f; ", minimumPSNR) +
+                           "Actual psnr = " + String.format("%.02f", psnr),
+                           false);
+            }
+        } finally {
+            rs.destroy();
         }
-        DepthOfFieldOptions current_depth_options = new DepthOfFieldOptions(current_rgbz);
-        RsTaskParams rsTaskParam = new RsTaskParams(rs, current_depth_options);
-
-        RenderScriptTask renderScriptTask = new RenderScriptTask(rs, impl);
-        Bitmap outputImage = renderScriptTask.applyRefocusFilter(rsTaskParam.mOptions);
-
-        Bitmap expectedImage = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.expected_output);
-
-        double psnr = ImageCompare.psnr(outputImage, expectedImage);
-        android.util.Log.i("RefocusTest", "psnr = " + String.format("%.02f", psnr));
-        if (psnr < minimumPSNR) {
-            MediaStoreSaver.savePNG(outputImage, "refocus", "refocus_output" , ctx);
-            assertTrue("Required minimum psnr = " + String.format("%.02f; ", minimumPSNR) +
-                       "Actual psnr = " + String.format("%.02f", psnr),
-                       false);
-        }
-        rs.destroy();
     }
 
 
diff --git a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
index 857ffd8..6b3abf6 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
@@ -15,6 +15,7 @@
  */
 package android.speech.tts.cts;
 
+import android.os.ConditionVariable;
 import android.media.AudioFormat;
 import android.os.ConditionVariable;
 import android.speech.tts.SynthesisCallback;
@@ -37,6 +38,10 @@
     // Object that onSynthesizeText will #block on, if set to non-null
     public static volatile ConditionVariable sSynthesizeTextWait;
 
+    // Condition variable that onSynthesizeText will #open when it started
+    // synethesizing, if set to non-null.
+    public static volatile ConditionVariable sSynthesizeTextStartEvent;
+
     private ArrayList<Locale> supportedLanguages = new ArrayList<Locale>();
     private ArrayList<Locale> supportedCountries = new ArrayList<Locale>();
     private ArrayList<Locale> GBFallbacks = new ArrayList<Locale>();
@@ -80,6 +85,11 @@
             return;
         }
 
+        final ConditionVariable synthesizeTextStartEvent = sSynthesizeTextStartEvent;
+        if (synthesizeTextStartEvent != null) {
+            sSynthesizeTextStartEvent.open();
+        }
+
         final ConditionVariable synthesizeTextWait = sSynthesizeTextWait;
         if (synthesizeTextWait != null) {
             synthesizeTextWait.block(10000);  // 10s timeout
diff --git a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
index 4d9faad..8e54d31 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
@@ -117,6 +117,27 @@
         }
     }
 
+    public void testSpeakStopBehindOtherAudioPlayback() throws Exception {
+        final ConditionVariable synthesizeTextWait = new ConditionVariable();
+        final ConditionVariable synthesizeTextStartEvent = new ConditionVariable();
+        StubTextToSpeechService.sSynthesizeTextWait = synthesizeTextWait;
+        StubTextToSpeechService.sSynthesizeTextStartEvent = synthesizeTextStartEvent;
+
+        // Make the audio playback queue busy by putting a 30s of silence.
+        getTts().stop();
+        getTts().playSilentUtterance(30000, TextToSpeech.QUEUE_ADD, "silence");
+
+        // speak(), wait it to starting in the service, and stop().
+        int result = getTts().speak(UTTERANCE, TextToSpeech.QUEUE_ADD, null, "stop");
+        assertEquals("speak() failed", TextToSpeech.SUCCESS, result);
+        assertTrue("synthesis not started", synthesizeTextStartEvent.block(10000));
+        getTts().stop();
+
+        // Wake up the Stubs #onSynthesizeSpeech (one that will be stopped in-progress)
+        synthesizeTextWait.open();
+
+        assertTrue("speak() stop callback timeout", mTts.waitForStop("stop"));
+    }
 
     public void testMediaPlayerFails() throws Exception {
         File sampleFile = new File(Environment.getExternalStorageDirectory(), "notsound.wav");
diff --git a/tests/tests/systemintents/Android.mk b/tests/tests/systemintents/Android.mk
index 573e2ee..77b28a4 100644
--- a/tests/tests/systemintents/Android.mk
+++ b/tests/tests/systemintents/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_PACKAGE_NAME := CtsSystemIntentTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test android-support-test
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java b/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java
index c572629..086f2cb 100644
--- a/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java
+++ b/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java
@@ -16,6 +16,8 @@
 
 package android.systemintents.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -23,14 +25,17 @@
 import android.net.Uri;
 import android.provider.Settings;
 import android.support.test.filters.MediumTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
-import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
-public class TestSystemIntents extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class TestSystemIntents {
+
     /*
      * List of activity intents defined by the system.  Activities to handle each of these
      * intents must all exist.
@@ -56,7 +61,6 @@
         }
     }
 
-    @Rule
     private final IntentEntry[] mTestIntents = {
             /* Settings-namespace intent actions */
             new IntentEntry(0, new Intent(Settings.ACTION_SETTINGS)),
@@ -76,7 +80,7 @@
 
     @Test
     public void testSystemIntents() {
-        final PackageManager pm = getContext().getPackageManager();
+        final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
         int productFlags = 0;
 
         if (pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
@@ -87,7 +91,7 @@
             productFlags |= EXCLUDE_NON_TELEPHONY;
         }
 
-        final Configuration config = getContext().getResources().getConfiguration();
+        final Configuration config = InstrumentationRegistry.getContext().getResources().getConfiguration();
         if ((config.uiMode & Configuration.UI_MODE_TYPE_WATCH) != 0) {
             productFlags |= EXCLUDE_WATCH;
         }
@@ -99,4 +103,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index fc0d841..453640d 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -23,6 +23,8 @@
     <application>
         <activity android:name=".LightBarActivity"
                 android:theme="@android:style/Theme.Material.NoActionBar"></activity>
+        <activity android:name=".LightBarThemeActivity"
+            android:theme="@style/LightBarTheme"></activity>
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/tests/tests/systemui/res/values/styles.xml b/tests/tests/systemui/res/values/styles.xml
new file mode 100644
index 0000000..e3e8a01
--- /dev/null
+++ b/tests/tests/systemui/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <style name="LightBarTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
+        <item name="android:windowLightStatusBar">true</item>
+        <item name="android:windowLightNavigationBar">true</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarThemeActivity.java b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeActivity.java
new file mode 100644
index 0000000..4ae2e35
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.systemui.cts;
+
+import android.app.Activity;
+
+public class LightBarThemeActivity extends Activity {
+}
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java
new file mode 100644
index 0000000..9fc6d58
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.systemui.cts;
+
+import android.os.SystemClock;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class LightBarThemeTest {
+
+    @Rule
+    public ActivityTestRule<LightBarThemeActivity> mActivityRule = new ActivityTestRule<>(
+            LightBarThemeActivity.class);
+
+    @Test
+    public void testThemeSetsFlags() {
+        final int flags = mActivityRule.getActivity().getWindow().getAttributes()
+                .systemUiVisibility;
+        Assert.assertTrue((flags & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0);
+        Assert.assertTrue((flags & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0);
+    }
+}
diff --git a/tests/tests/text/assets/ellipsis_test_font.ttf b/tests/tests/text/assets/ellipsis_test_font.ttf
new file mode 100644
index 0000000..ad0d79b
--- /dev/null
+++ b/tests/tests/text/assets/ellipsis_test_font.ttf
Binary files differ
diff --git a/tests/tests/text/assets/ellipsis_test_font.ttx b/tests/tests/text/assets/ellipsis_test_font.ttx
new file mode 100644
index 0000000..0c74b47
--- /dev/null
+++ b/tests/tests/text/assets/ellipsis_test_font.ttx
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+  <GlyphOrder>
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="a"/>
+    <GlyphID id="2" name="ellipsis"/>
+  </GlyphOrder>
+
+  <head>
+    <tableVersion value="1.0"/>
+    <fontRevision value="1.0"/>
+    <checkSumAdjustment value="0x640cdb2f"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00000011"/>
+    <unitsPerEm value="1000"/>
+    <created value="Fri Mar 17 07:26:00 2017"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="7"/>
+    <fontDirectionHint value="2"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="0x10000"/>
+    <ascent value="1000"/>
+    <descent value="-200"/>
+    <lineGap value="0"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+  </hhea>
+
+  <maxp>
+    <tableVersion value="0x10000"/>
+    <maxZones value="0"/>
+    <maxTwilightPoints value="0"/>
+    <maxStorage value="0"/>
+    <maxFunctionDefs value="0"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="0"/>
+    <maxSizeOfInstructions value="0"/>
+    <maxComponentElements value="0"/>
+  </maxp>
+
+  <OS_2>
+    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+         will be recalculated by the compiler -->
+    <version value="3"/>
+    <xAvgCharWidth value="594"/>
+    <usWeightClass value="400"/>
+    <usWidthClass value="5"/>
+    <fsType value="00000000 00001000"/>
+    <ySubscriptXSize value="650"/>
+    <ySubscriptYSize value="600"/>
+    <ySubscriptXOffset value="0"/>
+    <ySubscriptYOffset value="75"/>
+    <ySuperscriptXSize value="650"/>
+    <ySuperscriptYSize value="600"/>
+    <ySuperscriptXOffset value="0"/>
+    <ySuperscriptYOffset value="350"/>
+    <yStrikeoutSize value="50"/>
+    <yStrikeoutPosition value="300"/>
+    <sFamilyClass value="0"/>
+    <panose>
+      <bFamilyType value="0"/>
+      <bSerifStyle value="0"/>
+      <bWeight value="5"/>
+      <bProportion value="0"/>
+      <bContrast value="0"/>
+      <bStrokeVariation value="0"/>
+      <bArmStyle value="0"/>
+      <bLetterForm value="0"/>
+      <bMidline value="0"/>
+      <bXHeight value="0"/>
+    </panose>
+    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+    <achVendID value="UKWN"/>
+    <fsSelection value="00000000 01000000"/>
+    <usFirstCharIndex value="32"/>
+    <usLastCharIndex value="122"/>
+    <sTypoAscender value="800"/>
+    <sTypoDescender value="-200"/>
+    <sTypoLineGap value="200"/>
+    <usWinAscent value="1000"/>
+    <usWinDescent value="200"/>
+    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+    <sxHeight value="500"/>
+    <sCapHeight value="700"/>
+    <usDefaultChar value="0"/>
+    <usBreakChar value="32"/>
+    <usMaxContext value="0"/>
+  </OS_2>
+
+  <hmtx>
+    <mtx name=".notdef" width="500" lsb="0"/>
+    <mtx name="a" width="1000" lsb="0"/>
+    <mtx name="ellipsis" width="1000" lsb="0"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_4 platformID="3" platEncID="10" language="0">
+      <map code="0x0061" name="a" /> <!-- LATIN SMALL LETTER A -->
+      <map code="0x2026" name="ellipsis" /> <!-- HORIZONTAL ELLIPSIS -->
+    </cmap_format_4>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="ellipsis" xMin="0" yMin="0" xMax="0" yMax="0" />
+  </glyf>
+
+  <name>
+    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+      Copyright (C) 2017 The Android Open Source Project
+    </namerecord>
+    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+      SampleFont-Regular
+    </namerecord>
+    <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      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.
+    </namerecord>
+    <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+      http://www.apache.org/licenses/LICENSE-2.0
+    </namerecord>
+  </name>
+
+  <post>
+    <formatType value="3.0"/>
+    <italicAngle value="0.0"/>
+    <underlinePosition value="-75"/>
+    <underlineThickness value="50"/>
+    <isFixedPitch value="0"/>
+    <minMemType42 value="0"/>
+    <maxMemType42 value="0"/>
+    <minMemType1 value="0"/>
+    <maxMemType1 value="0"/>
+  </post>
+
+  <GPOS>
+    <Version value="0x00010000"/>
+    <ScriptList>
+      <!-- ScriptCount=1 -->
+      <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+    </ScriptList>
+    <FeatureList>
+      <!-- FeatureCount=1 -->
+      <FeatureRecord index="0">
+        <FeatureTag value="kern"/>
+        <Feature>
+          <!-- LookupCount=1 -->
+          <LookupListIndex index="0" value="0"/>
+        </Feature>
+      </FeatureRecord>
+    </FeatureList>
+    <LookupList>
+      <!-- LookupCount=1 -->
+      <Lookup index="0">
+        <LookupType value="2"/>
+        <LookupFlag value="0"/>
+        <PairPos index="0" Format="1">
+          <Coverage Format="1">
+            <Glyph value="a"/>
+            <Glyph value="ellipsis"/>
+          </Coverage>
+          <ValueFormat1 value="4"/>
+          <ValueFormat2 value="0"/>
+          <PairSet index="0">
+            <PairValueRecord index="0">
+              <SecondGlyph value="ellipsis"/>
+              <Value1 XAdvance="500"/>
+            </PairValueRecord>
+          </PairSet>
+          <PairSet index="1">
+            <PairValueRecord index="0">
+              <SecondGlyph value="a"/>
+              <Value1 XAdvance="500"/>
+            </PairValueRecord>
+          </PairSet>
+        </PairPos>
+      </Lookup>
+    </LookupList>
+  </GPOS>
+</ttFont>
diff --git a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
index e78fb3e..f2a7b5a 100644
--- a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyFloat;
 import static org.mockito.Matchers.anyInt;
@@ -36,6 +37,8 @@
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.BoringLayout;
@@ -345,6 +348,91 @@
                 anyInt(), anyInt(), anyFloat(), anyFloat(), any(Paint.class));
     }
 
+    @Test
+    public void testEllipsize_End() {
+        // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think "aa…"
+        // would fit, but after measuring the new text, we find that it doesn't and we need to
+        // retry.
+        final float size = 100.0f;
+        final int allocatedWidth = (int) (3.4f * size);
+        final BoringLayout layout = new BoringLayout(
+                "aaaa",
+                getTextPaintForEllipsize(size),
+                allocatedWidth,
+                DEFAULT_ALIGN,
+                SPACING_MULT_NO_SCALE,
+                SPACING_ADD_NO_SCALE,
+                createMetrics(0, 0, 0, 0, allocatedWidth, 0),
+                false /* includepad */,
+                TextUtils.TruncateAt.END,
+                allocatedWidth);
+        assertEquals("a\u2026\uFEFF\uFEFF", layout.getText().toString());
+    }
+
+    @Test
+    public void testEllipsize_Start() {
+        // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think "…aa"
+        // would fit, but after measuring the new text, we find that it doesn't and we need to
+        // retry.
+        final float size = 100.0f;
+        final int allocatedWidth = (int) (3.4f * size);
+        final BoringLayout layout = new BoringLayout(
+                "aaaa",
+                getTextPaintForEllipsize(size),
+                allocatedWidth,
+                DEFAULT_ALIGN,
+                SPACING_MULT_NO_SCALE,
+                SPACING_ADD_NO_SCALE,
+                createMetrics(0, 0, 0, 0, allocatedWidth, 0),
+                false /* includepad */,
+                TextUtils.TruncateAt.START,
+                allocatedWidth);
+        assertEquals("\u2026\uFEFF\uFEFFa", layout.getText().toString());
+    }
+
+    @Test
+    public void testEllipsize_Middle() {
+        // When we try to ellipsize "aaaaaa" into a thinner 5.9 em space, we originally think
+        // "aa…aa" would fit, but after measuring the new text, we find that it doesn't and we need
+        // to retry.
+        final float size = 100.0f;
+        final int allocatedWidth = (int) (5.9f * size);
+        final BoringLayout layout = new BoringLayout(
+                "aaaaaa",
+                getTextPaintForEllipsize(size),
+                allocatedWidth,
+                DEFAULT_ALIGN,
+                SPACING_MULT_NO_SCALE,
+                SPACING_ADD_NO_SCALE,
+                createMetrics(0, 0, 0, 0, allocatedWidth, 0),
+                false /* includepad */,
+                TextUtils.TruncateAt.MIDDLE,
+                allocatedWidth);
+        final String ellipsizedString = layout.getText().toString();
+        assertTrue("aa\u2026\uFEFF\uFEFFa".equals(ellipsizedString)
+                || "a\u2026\uFEFF\uFEFFaa".equals(ellipsizedString));
+    }
+
+    private TextPaint getTextPaintForEllipsize(float size) {
+        // The font used in this method has two glyphs defined for "a" and ellipsis. Both are one
+        // em wide. But the glyphs are kerned: whenever the "a" is followed or preceded by an
+        // ellipsis, half an em is added between them as kerning. This means that:
+        // "aaaa" is 4 ems wide,
+        // "aaa…" is 4.5 ems wide,
+        // "aa…" is 3.5 ems wide,
+        // "a…" is 2.5 ems wide,
+        // "aa…aa" is 6 ems wide,
+        // "aa…a" is 5 ems wide,
+        // "a…aa" is 5 ems wide,
+        // "a…a" is 4 ems wide,
+        // "…a" is 2.5 ems wide.
+        final TextPaint paint = new TextPaint();
+        paint.setTypeface(Typeface.createFromAsset(
+                InstrumentationRegistry.getTargetContext().getAssets(), "ellipsis_test_font.ttf"));
+        paint.setTextSize(size);
+        return paint;
+    }
+
     private static Metrics createMetrics(
             final int top,
             final int ascent,
diff --git a/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java b/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
index 02139c5..d37f0ca 100644
--- a/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
@@ -29,6 +29,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.text.DynamicLayout;
 import android.text.Layout;
+import android.text.SpannableStringBuilder;
 import android.text.StaticLayout;
 import android.text.TextPaint;
 import android.text.TextUtils;
@@ -44,6 +45,7 @@
     private static final float SPACING_MULT_NO_SCALE = 1.0f;
     private static final float SPACING_ADD_NO_SCALE = 0.0f;
     private static final int DEFAULT_OUTER_WIDTH = 150;
+    private static final int ELLIPSIZE_WIDTH = 8;
     private static final CharSequence SINGLELINE_CHAR_SEQUENCE = "......";
     private static final String[] TEXT = {"CharSequence\n", "Char\tSequence\n", "CharSequence"};
     private static final CharSequence MULTLINE_CHAR_SEQUENCE = TEXT[0] + TEXT[1] + TEXT[2];
@@ -110,7 +112,7 @@
                 DEFAULT_ALIGN,
                 SPACING_MULT_NO_SCALE,
                 SPACING_ADD_NO_SCALE,
-                true,
+                true /* include pad */,
                 TextUtils.TruncateAt.START,
                 DEFAULT_OUTER_WIDTH);
         assertEquals(0, dynamicLayout.getEllipsisCount(LINE1));
@@ -118,6 +120,24 @@
         assertEquals(DEFAULT_OUTER_WIDTH, dynamicLayout.getEllipsizedWidth());
     }
 
+    // This could cause a crash in an older version of ellipsization code.
+    @Test
+    public void testEllipsisWithReflow() {
+        final String text = "Ham & Cheese.sandwich";
+        final int width = 1 << 20;
+        final int ellipsizedWidth = 2 * (int) mDefaultPaint.getTextSize();
+        final DynamicLayout dynamicLayout = new DynamicLayout(text,
+                text,
+                mDefaultPaint,
+                width,
+                DEFAULT_ALIGN,
+                SPACING_MULT_NO_SCALE,
+                SPACING_ADD_NO_SCALE,
+                true /* include pad */,
+                TextUtils.TruncateAt.END,
+                ellipsizedWidth);
+    }
+
     /*
      * Test whether include the padding to calculate the layout.
      * 1. Include padding while calculate the layout.
@@ -194,6 +214,62 @@
         assertEquals(TEXT[0].length() + TEXT[1].length(), mDynamicLayout.getLineStart(LINE2));
     }
 
+    @Test
+    public void testLineSpacing() {
+        SpannableStringBuilder text = new SpannableStringBuilder("a\nb\nc");
+        final float spacingMultiplier = 2f;
+        final float spacingAdd = 4;
+        final int width = 1000;
+        final TextPaint textPaint = new TextPaint();
+        // create the DynamicLayout
+        final DynamicLayout dynamicLayout = new DynamicLayout(text,
+                textPaint,
+                width,
+                ALIGN_NORMAL,
+                spacingMultiplier,
+                spacingAdd,
+                false /*includepad*/);
+
+        // create a StaticLayout with same text, this will define the expectations
+        Layout expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+                spacingMultiplier);
+        assertLineSpecs(expected, dynamicLayout);
+
+        // add a new line to the end, DynamicLayout will re-calculate
+        text = text.append("\nd");
+        expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+                spacingMultiplier);
+        assertLineSpecs(expected, dynamicLayout);
+
+        // insert a next line and a char as the new second line
+        text = text.insert(TextUtils.indexOf(text, '\n') + 1, "a1\n");
+        expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+                spacingMultiplier);
+        assertLineSpecs(expected, dynamicLayout);
+    }
+
+    @Test
+    public void testLineSpacing_textEndingWithNextLine() {
+        final SpannableStringBuilder text = new SpannableStringBuilder("a\n");
+        final float spacingMultiplier = 2f;
+        final float spacingAdd = 4f;
+        final int width = 1000;
+        final TextPaint textPaint = new TextPaint();
+        // create the DynamicLayout
+        final DynamicLayout dynamicLayout = new DynamicLayout(text,
+                textPaint,
+                width,
+                ALIGN_NORMAL,
+                spacingMultiplier,
+                spacingAdd,
+                false /*includepad*/);
+
+        // create a StaticLayout with same text, this will define the expectations
+        final Layout expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+                spacingMultiplier);
+        assertLineSpecs(expected, dynamicLayout);
+    }
+
     private Layout createStaticLayout(CharSequence text, TextPaint textPaint, int width,
             float spacingAdd, float spacingMultiplier) {
         return StaticLayout.Builder.obtain(text, 0,
@@ -253,4 +329,93 @@
                 spacingMultiplier);
         assertLineSpecs(expected, dynamicLayout);
     }
+
+    @Test
+    public void testBuilder_obtain() {
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+                mDefaultPaint, DEFAULT_OUTER_WIDTH);
+        final DynamicLayout layout = builder.build();
+        // Check values passed to obtain().
+        assertEquals(MULTLINE_CHAR_SEQUENCE, layout.getText());
+        assertEquals(mDefaultPaint, layout.getPaint());
+        assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth());
+        // Check default values.
+        assertEquals(Layout.Alignment.ALIGN_NORMAL, layout.getAlignment());
+        assertEquals(0.0f, layout.getSpacingAdd(), 0.0f);
+        assertEquals(1.0f, layout.getSpacingMultiplier(), 0.0f);
+        assertEquals(DEFAULT_OUTER_WIDTH, layout.getEllipsizedWidth());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testBuilder_obtainWithNullText() {
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(null, mDefaultPaint, 0);
+        final DynamicLayout layout = builder.build();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testBuilder_obtainWithNullPaint() {
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+                null, 0);
+        final DynamicLayout layout = builder.build();
+    }
+
+    @Test
+    public void testBuilder_setDisplayTest() {
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+                mDefaultPaint, DEFAULT_OUTER_WIDTH);
+        builder.setDisplayText(SINGLELINE_CHAR_SEQUENCE);
+        final DynamicLayout layout = builder.build();
+        assertEquals(SINGLELINE_CHAR_SEQUENCE, layout.getText());
+    }
+
+    @Test
+    public void testBuilder_setAlignment() {
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+                mDefaultPaint, DEFAULT_OUTER_WIDTH);
+        builder.setAlignment(DEFAULT_ALIGN);
+        final DynamicLayout layout = builder.build();
+        assertEquals(DEFAULT_ALIGN, layout.getAlignment());
+    }
+
+    @Test
+    public void testBuilder_setLineSpacing() {
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+                mDefaultPaint, DEFAULT_OUTER_WIDTH);
+        builder.setLineSpacing(1.0f, 2.0f);
+        final DynamicLayout layout = builder.build();
+        assertEquals(1.0f, layout.getSpacingAdd(), 0.0f);
+        assertEquals(2.0f, layout.getSpacingMultiplier(), 0.0f);
+    }
+
+    @Test
+    public void testBuilder_ellipsization() {
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+                mDefaultPaint, DEFAULT_OUTER_WIDTH);
+        builder.setEllipsize(TextUtils.TruncateAt.END)
+                .setEllipsizedWidth(ELLIPSIZE_WIDTH);
+        final DynamicLayout layout = builder.build();
+        assertEquals(ELLIPSIZE_WIDTH, layout.getEllipsizedWidth());
+        assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth());
+        for (int i = 0; i < TEXT.length; i++) {
+            if (i == TEXT.length - 1) { // last line
+                assertTrue(layout.getEllipsisCount(i) > 0);
+            } else {
+                assertEquals(0, layout.getEllipsisCount(i));
+            }
+        }
+    }
+
+    @Test
+    public void testBuilder_otherSetters() {
+        // Setter methods that cannot be directly tested.
+        // setBreakStrategy, setHyphenationFrequency, setIncludePad, and setJustificationMode.
+        final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+                mDefaultPaint, DEFAULT_OUTER_WIDTH);
+        builder.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
+                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL)
+                .setIncludePad(true)
+                .setJustificationMode(Layout.JUSTIFICATION_MODE_INTER_WORD);
+        final DynamicLayout layout = builder.build();
+        assertNotNull(layout);
+    }
 }
diff --git a/tests/tests/text/src/android/text/cts/SelectionTest.java b/tests/tests/text/src/android/text/cts/SelectionTest.java
index f920bda..2aac83b 100644
--- a/tests/tests/text/src/android/text/cts/SelectionTest.java
+++ b/tests/tests/text/src/android/text/cts/SelectionTest.java
@@ -23,6 +23,7 @@
 
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.Layout;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.StaticLayout;
@@ -275,6 +276,56 @@
     }
 
     @Test
+    public void testMoveUpAfterTyping() {
+        CharSequence text = "aaa\nmm";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 1, 1);
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(5, Selection.getSelectionStart(builder));
+        assertEquals(5, Selection.getSelectionEnd(builder));
+
+        builder.insert(5, "mm");
+        layout = new StaticLayout(builder, new TextPaint(), 200, Layout.Alignment.ALIGN_NORMAL,
+                0, 0, false);
+        assertEquals(7, Selection.getSelectionStart(builder));
+        assertEquals(7, Selection.getSelectionEnd(builder));
+
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(3, Selection.getSelectionEnd(builder));
+    }
+
+    @Test
+    public void testMoveUpKeepsOriginalMemoryPosition() {
+        CharSequence text = "aa\nm";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.setSelection(builder, 1, 1);
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(4, Selection.getSelectionStart(builder));
+        assertEquals(4, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+    }
+
+    @Test
     public void testMoveDown() {
         CharSequence text = "hello,world\nGoogle";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -313,6 +364,340 @@
     }
 
     @Test
+    public void testMoveDownAfterTyping() {
+        CharSequence text = "mm\naaa";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 4, 4);
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+
+        builder.insert(1, "mm");
+        layout = new StaticLayout(builder, new TextPaint(), 200, Layout.Alignment.ALIGN_NORMAL,
+                0, 0, false);
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(3, Selection.getSelectionEnd(builder));
+
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(8, Selection.getSelectionStart(builder));
+        assertEquals(8, Selection.getSelectionEnd(builder));
+    }
+
+    @Test
+    public void testMoveDownKeepsOriginalMemoryPosition() {
+        CharSequence text = "m\naa";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.setSelection(builder, 3, 3);
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(3, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+    }
+
+    @Test
+    public void testMemoryPositionResetByHorizontalMovement() {
+        CharSequence text = "m\naa";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.setSelection(builder, 3, 3);
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(3, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveRight(builder, layout));
+        assertEquals(4, Selection.getSelectionStart(builder));
+        assertEquals(4, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(4, Selection.getSelectionStart(builder));
+        assertEquals(4, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveLeft(builder, layout));
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(3, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.setSelection(builder, 3, 3);
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+    }
+
+    @Test
+    public void testMemoryPositionResetByRemoveSelection() {
+        CharSequence text = "m\naa";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.setSelection(builder, 3, 3);
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.removeSelection(builder);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+    }
+
+    @Test
+    public void testMultilineLengthMoveDown() {
+        CharSequence text = "a\n\na";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 1);
+        // Move down to empty line
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(2, Selection.getSelectionStart(builder));
+        assertEquals(2, Selection.getSelectionEnd(builder));
+
+        // Move down to third line
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(4, Selection.getSelectionStart(builder));
+        assertEquals(4, Selection.getSelectionEnd(builder));
+    }
+
+    @Test
+    public void testMultilineLengthExtendDown() {
+        CharSequence text = "Google\n\nhello, world";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 1, 3);
+        assertTrue(Selection.extendDown(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(7, Selection.getSelectionEnd(builder));
+
+        assertTrue(Selection.extendDown(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(15, Selection.getSelectionEnd(builder));
+
+        assertTrue(Selection.extendDown(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(text.length(), Selection.getSelectionEnd(builder));
+    }
+
+    @Test
+    public void testExtendDownKeepsOriginalMemoryPosition() {
+        CharSequence text = "m\naa";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.setSelection(builder, 3, 3);
+        assertTrue(Selection.extendUp(builder, layout));
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.extendDown(builder, layout));
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(3, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+    }
+
+    @Test
+    public void testMultilineLengthMoveUp() {
+        CharSequence text = "a\n\na";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 4);
+        // Move up to empty line
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(2, Selection.getSelectionStart(builder));
+        assertEquals(2, Selection.getSelectionEnd(builder));
+
+        // Move up to first line
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+    }
+
+    @Test
+    public void testMultilineLengthExtendUp() {
+        CharSequence text = "Google\n\nhello, world";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        assertTrue(Selection.extendUp(builder, layout));
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(0, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 9, 16);
+        assertTrue(Selection.extendUp(builder, layout));
+        assertEquals(9, Selection.getSelectionStart(builder));
+        assertEquals(7, Selection.getSelectionEnd(builder));
+
+        assertTrue(Selection.extendUp(builder, layout));
+        assertEquals(9, Selection.getSelectionStart(builder));
+        assertEquals(4, Selection.getSelectionEnd(builder));
+
+        assertTrue(Selection.extendUp(builder, layout));
+        assertEquals(9, Selection.getSelectionStart(builder));
+        assertEquals(0, Selection.getSelectionEnd(builder));
+    }
+
+    @Test
+    public void testExtendUpKeepsOriginalMemoryPosition() {
+        CharSequence text = "aa\nm";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+                Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+        assertEquals(0,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        Selection.setSelection(builder, 1, 1);
+        assertTrue(Selection.extendDown(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(4, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+        assertTrue(Selection.extendUp(builder, layout));
+        assertEquals(1, Selection.getSelectionStart(builder));
+        assertEquals(1, Selection.getSelectionEnd(builder));
+        assertEquals(1,
+                builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+    }
+
+    @Test
+    public void testMultilineLengthMoveDownAfterSelection() {
+        CharSequence text = "aaaaa\n\naaaaa";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 3);
+        // Move down to empty line
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(6, Selection.getSelectionStart(builder));
+        assertEquals(6, Selection.getSelectionEnd(builder));
+
+        // Move down to third line
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(3, Selection.getSelectionStart(builder));
+        assertEquals(3, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 5);
+        // Move down to empty line
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(6, Selection.getSelectionStart(builder));
+        assertEquals(6, Selection.getSelectionEnd(builder));
+
+        // Move down to third line
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(5, Selection.getSelectionStart(builder));
+        assertEquals(5, Selection.getSelectionEnd(builder));
+    }
+
+    @Test
+    public void testMultilineLengthMoveUpAfterSelection() {
+        CharSequence text = "aaaaa\n\naaaaa";
+        SpannableStringBuilder builder = new SpannableStringBuilder(text);
+        StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+        assertEquals(-1, Selection.getSelectionStart(builder));
+        assertEquals(-1, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 10);
+        // Move up to empty line
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(6, Selection.getSelectionStart(builder));
+        assertEquals(6, Selection.getSelectionEnd(builder));
+
+        // Move down to third line
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(10, Selection.getSelectionStart(builder));
+        assertEquals(10, Selection.getSelectionEnd(builder));
+
+        Selection.setSelection(builder, 12);
+        // Move up to empty line
+        assertTrue(Selection.moveUp(builder, layout));
+        assertEquals(6, Selection.getSelectionStart(builder));
+        assertEquals(6, Selection.getSelectionEnd(builder));
+
+        // Move down to third line
+        assertTrue(Selection.moveDown(builder, layout));
+        assertEquals(12, Selection.getSelectionStart(builder));
+        assertEquals(12, Selection.getSelectionEnd(builder));
+    }
+
+    @Test
     public void testExtendSelection() {
         CharSequence text = "hello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 4f022a5..bc714b2 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -23,7 +23,9 @@
 import static org.junit.Assert.fail;
 
 import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
+import android.support.test.filters.Suppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.Editable;
 import android.text.Layout;
@@ -59,6 +61,13 @@
     private static final int LINE_COUNT = 6;
     private static final int LARGER_THAN_LINE_COUNT  = 50;
 
+    private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing "
+            + "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad "
+            + "minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
+            + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse "
+            + "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "
+            + "proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+
     /* the first line must have one tab. the others not. totally 6 lines
      */
     private static final CharSequence LAYOUT_TEXT = "CharSe\tq\nChar"
@@ -203,8 +212,8 @@
             // setBreakStrategy, setHyphenationFrequency, setIncludePad, and setIndents.
             StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
                     LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
-            builder.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY);
-            builder.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_FULL);
+            builder.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY);
+            builder.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
             builder.setIncludePad(true);
             builder.setIndents(null, null);
             StaticLayout layout = builder.build();
@@ -213,6 +222,38 @@
     }
 
     @Test
+    public void testSetLineSpacing_whereLineEndsWithNextLine() {
+        final float spacingAdd = 10f;
+        final float spacingMult = 3f;
+
+        // two lines of text, with line spacing, first line will have the spacing, but last line
+        // wont have the spacing
+        final String tmpText = "a\nb";
+        StaticLayout.Builder builder = StaticLayout.Builder.obtain(tmpText, 0, tmpText.length(),
+                mDefaultPaint, DEFAULT_OUTER_WIDTH);
+        builder.setLineSpacing(spacingAdd, spacingMult).setIncludePad(false);
+        final StaticLayout comparisonLayout = builder.build();
+
+        assertEquals(2, comparisonLayout.getLineCount());
+        final int heightWithLineSpacing = comparisonLayout.getLineBottom(0)
+                - comparisonLayout.getLineTop(0);
+        final int heightWithoutLineSpacing = comparisonLayout.getLineBottom(1)
+                - comparisonLayout.getLineTop(1);
+        assertTrue(heightWithLineSpacing > heightWithoutLineSpacing);
+
+        final String text = "a\n";
+        // build the layout to be tested
+        builder = StaticLayout.Builder.obtain("a\n", 0, text.length(), mDefaultPaint,
+                DEFAULT_OUTER_WIDTH);
+        builder.setLineSpacing(spacingAdd, spacingMult).setIncludePad(false);
+        final StaticLayout layout = builder.build();
+
+        assertEquals(comparisonLayout.getLineCount(), layout.getLineCount());
+        assertEquals(heightWithLineSpacing, layout.getLineBottom(0) - layout.getLineTop(0));
+        assertEquals(heightWithoutLineSpacing, layout.getLineBottom(1) - layout.getLineTop(1));
+    }
+
+    @Test
     public void testBuilder_setJustificationMode() {
         StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
                 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
@@ -222,6 +263,7 @@
         // without causing any exceptions.
         assertNotNull(layout);
     }
+
     /*
      * Get the line number corresponding to the specified vertical position.
      *  If you ask for a position above 0, you get 0. above 0 means pixel above the fire line
@@ -1171,6 +1213,91 @@
         assertTrue(layout.getEllipsisStart(0) != 0);
     }
 
+    @Test
+    public void testEllipsize_retryEnd() {
+        final float size = 100.0f;
+
+        final int allocatedWidth = (int) (3.4f * size);
+        final String text = "aaaa";
+        final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+                getTextPaintForEllipsize(size), allocatedWidth)
+                .setEllipsize(TextUtils.TruncateAt.END)
+                .setEllipsizedWidth(allocatedWidth)
+                .setMaxLines(1)
+                .build();
+        assertEquals(1, layout.getEllipsisStart(0)); // After the first 'a'
+        assertEquals(3, layout.getEllipsisCount(0));
+    }
+
+    @Test
+    public void testEllipsize_retryEndRtl() {
+        final float size = 100.0f;
+
+        final int allocatedWidth = (int) (3.4f * size);
+        final String text = "\u202Eaaaa"; // U+202E is the RIGHT-TO-LEFT OVERRIDE.
+        final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+                getTextPaintForEllipsize(size), allocatedWidth)
+                .setEllipsize(TextUtils.TruncateAt.END)
+                .setEllipsizedWidth(allocatedWidth)
+                .setMaxLines(1)
+                .build();
+        assertEquals(2, layout.getEllipsisStart(0)); // After the first 'a'
+        assertEquals(3, layout.getEllipsisCount(0));
+    }
+
+    @Test
+    public void testEllipsize_retryStart() {
+        final float size = 100.0f;
+
+        final int allocatedWidth = (int) (3.4f * size);
+        final String text = "aaaa";
+        final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+                getTextPaintForEllipsize(size), allocatedWidth)
+                .setEllipsize(TextUtils.TruncateAt.START)
+                .setEllipsizedWidth(allocatedWidth)
+                .setMaxLines(1)
+                .build();
+        assertEquals(0, layout.getEllipsisStart(0));
+        assertEquals(3, layout.getEllipsisCount(0));
+    }
+
+    @Test
+    public void testEllipsize_retryMiddle() {
+        final float size = 100.0f;
+
+        final int allocatedWidth = (int) (5.9f * size);
+        final String text = "aaaaaa";
+        final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+                getTextPaintForEllipsize(size), allocatedWidth)
+                .setEllipsize(TextUtils.TruncateAt.MIDDLE)
+                .setEllipsizedWidth(allocatedWidth)
+                .setMaxLines(1)
+                .build();
+        final int ellipsisStart = layout.getEllipsisStart(0);
+        assertTrue(ellipsisStart == 1 || ellipsisStart == 2);
+        assertEquals(3, layout.getEllipsisCount(0));
+    }
+
+    private TextPaint getTextPaintForEllipsize(float size) {
+        // The font used in this method has two glyphs defined for "a" and ellipsis. Both are one
+        // em wide. But the glyphs are kerned: whenever the "a" is followed or preceded by an
+        // ellipsis, half an em is added between them as kerning. This means that:
+        // "aaaa" is 4 ems wide,
+        // "aaa…" is 4.5 ems wide,
+        // "aa…" is 3.5 ems wide,
+        // "a…" is 2.5 ems wide,
+        // "aa…aa" is 6 ems wide,
+        // "aa…a" is 5 ems wide,
+        // "a…aa" is 5 ems wide,
+        // "a…a" is 4 ems wide,
+        // "…a" is 2.5 ems wide.
+        final TextPaint paint = new TextPaint();
+        paint.setTypeface(Typeface.createFromAsset(
+                InstrumentationRegistry.getTargetContext().getAssets(), "ellipsis_test_font.ttf"));
+        paint.setTextSize(size);
+        return paint;
+    }
+
     @Test(expected = IndexOutOfBoundsException.class)
     public void testGetPrimary_shouldFail_whenOffsetIsOutOfBounds_withSpannable() {
         final String text = "1\n2\n3";
@@ -1190,4 +1317,38 @@
                 .setEllipsize(TruncateAt.END).build();
         layout.getPrimaryHorizontal(layout.getText().length());
     }
+
+    // TODO: Re-enable once http://b/65207701 is fixed.
+    @Test
+    @Suppress
+    public void testGetLineWidth() {
+        final float wholeWidth = mDefaultPaint.measureText(LOREM_IPSUM);
+        final int lineWidth = (int) (wholeWidth / 10.0f);  // Make 10 lines per paragraph.
+        final String multiParaTestString =
+                LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM;
+        final Layout layout = StaticLayout.Builder.obtain(multiParaTestString, 0,
+                multiParaTestString.length(), mDefaultPaint, lineWidth)
+                .build();
+        for (int i = 0; i < layout.getLineCount(); i++) {
+            assertTrue(layout.getLineWidth(i) <= lineWidth);
+        }
+    }
+
+    // TODO: Re-enable once http://b/65207701 is fixed.
+    @Test
+    @Suppress
+    public void testIndent() {
+        final float wholeWidth = mDefaultPaint.measureText(LOREM_IPSUM);
+        final int lineWidth = (int) (wholeWidth / 10.0f);  // Make 10 lines per paragraph.
+        final int indentWidth = (int) (lineWidth * 0.3f);  // Make 30% indent.
+        final String multiParaTestString =
+                LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM;
+        final Layout layout = StaticLayout.Builder.obtain(multiParaTestString, 0,
+                multiParaTestString.length(), mDefaultPaint, lineWidth)
+                .setIndents(new int[] { indentWidth }, null)
+                .build();
+        for (int i = 0; i < layout.getLineCount(); i++) {
+            assertTrue(layout.getLineWidth(i) <= lineWidth - indentWidth);
+        }
+    }
 }
diff --git a/tests/tests/text/src/android/text/cts/TextUtilsTest.java b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
index d549cfa..2364dad 100644
--- a/tests/tests/text/src/android/text/cts/TextUtilsTest.java
+++ b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
@@ -706,6 +706,83 @@
         }
     }
 
+    @Test
+    public void testEllipsize_retryEnd() {
+        // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think
+        // "aa…" would fit, but after measuring the new text, we find that it doesn't and we need
+        // to retry.
+        final float size = 100.0f;
+        final String text = "aaaa";
+
+        final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+                3.4f * size,
+                TextUtils.TruncateAt.END, false /* preserveLength */, null /* callback */);
+        assertEquals("a\u2026", ellipsized.toString());
+    }
+
+    @Test
+    public void testEllipsize_retryEndRtl() {
+        // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think
+        // "aa…" would fit, but after measuring the new text, we find that it doesn't and we need
+        // to retry.
+        final float size = 100.0f;
+        final String text = "\u202Eaaaa"; // U+202E is the RIGHT-TO-LEFT OVERRIDE.
+
+        final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+                3.4f * size,
+                TextUtils.TruncateAt.END, false /* preserveLength */, null /* callback */);
+        assertEquals("\u202Ea\u2026", ellipsized.toString());
+    }
+
+    @Test
+    public void testEllipsize_retryStart() {
+        // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think
+        // "…aa" would fit, but after measuring the new text, we find that it doesn't and we need
+        // to retry.
+        final float size = 100.0f;
+        final String text = "aaaa";
+
+        final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+                3.4f * size,
+                TextUtils.TruncateAt.START, false /* preserveLength */, null /* callback */);
+        assertEquals("\u2026a", ellipsized.toString());
+    }
+
+    @Test
+    public void testEllipsize_retryMiddle() {
+        // When we try to ellipsize "aaaaaa" into a thinner 5.9 em space, we originally think
+        // "aa…aa" would fit, but after measuring the new text, we find that it doesn't and we need
+        // to retry.
+        final float size = 100.0f;
+        final String text = "aaaaaa";
+
+        final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+                5.9f * size,
+                TextUtils.TruncateAt.MIDDLE, false /* preserveLength */, null /* callback */);
+        final String ellipsizedString = ellipsized.toString();
+        assertTrue("aa\u2026a".equals(ellipsizedString) || "a\u2026aa".equals(ellipsizedString));
+    }
+
+    private TextPaint getTextPaintForEllipsize(float size) {
+        // The font used in this method has two glyphs defined for "a" and ellipsis. Both are one
+        // em wide. But the glyphs are kerned: whenever the "a" is followed or preceded by an
+        // ellipsis, half an em is added between them as kerning. This means that:
+        // "aaaa" is 4 ems wide,
+        // "aaa…" is 4.5 ems wide,
+        // "aa…" is 3.5 ems wide,
+        // "a…" is 2.5 ems wide,
+        // "aa…aa" is 6 ems wide,
+        // "aa…a" is 5 ems wide,
+        // "a…aa" is 5 ems wide,
+        // "a…a" is 4 ems wide,
+        // "…a" is 2.5 ems wide.
+        final TextPaint paint = new TextPaint();
+        paint.setTypeface(Typeface.createFromAsset(
+                InstrumentationRegistry.getTargetContext().getAssets(), "ellipsis_test_font.ttf"));
+        paint.setTextSize(size);
+        return paint;
+    }
+
     /**
      * Get a blank string which is filled up by '\uFEFF'.
      *
@@ -1614,6 +1691,8 @@
         spannableStringTokens.add(new SpannableString("span 2"));
         spannableStringTokens.add(new SpannableString("span 3"));
         assertEquals("span 1;span 2;span 3", TextUtils.join(";", spannableStringTokens));
+
+        assertEquals("", TextUtils.join("|", new ArrayList<CharSequence>()));
     }
 
     @Test(expected=NullPointerException.class)
@@ -1636,6 +1715,8 @@
                 new SpannableString("span 2"),
                 new SpannableString("span 3") };
         assertEquals("span 1;span 2;span 3", TextUtils.join(";", spannableStringTokens));
+
+        assertEquals("", TextUtils.join("|", new String[0]));
     }
 
     @Test(expected=NullPointerException.class)
diff --git a/tests/tests/text/src/android/text/format/cts/DateFormatTest.java b/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
index 13c9aa2..50c97b2 100644
--- a/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
+++ b/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
@@ -18,12 +18,15 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.app.UiAutomation;
 import android.content.Context;
+import android.content.res.Configuration;
+import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 import android.provider.Settings;
 import android.support.annotation.NonNull;
@@ -312,6 +315,27 @@
         }
     }
 
+    @Test
+    public void test_ContextLocaleIsUsed() {
+        final Locale oldLocale = Locale.getDefault();
+
+        try {
+            Date date = new Date(YEAR_FROM_1900, MONTH, DAY);
+            Locale.setDefault(Locale.FRANCE);
+            final String javaResult = java.text.DateFormat.getDateInstance(
+                    java.text.DateFormat.LONG).format(date);
+
+            final Configuration config = new Configuration();
+            config.setLocales(new LocaleList(Locale.JAPAN));
+            final Context context = mContext.createConfigurationContext(config);
+            final String androidResult = DateFormat.getLongDateFormat(context).format(date);
+
+            assertNotEquals(javaResult, androidResult);
+        } finally {
+            Locale.setDefault(oldLocale);
+        }
+    }
+
     @NonNull
     private String getTimeFormat() throws IOException {
         return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
index 9c96519..4f26aea 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.SystemClock;
 import android.text.cts.R;
 import android.text.method.BaseKeyListener;
 import android.text.method.DateKeyListener;
@@ -29,7 +28,6 @@
 import android.text.method.QwertyKeyListener;
 import android.text.method.TextKeyListener;
 import android.text.method.TimeKeyListener;
-import android.util.Log;
 
 /**
  * This Activity is used for testing:
@@ -55,47 +53,9 @@
  */
 
 public class KeyListenerCtsActivity extends Activity {
-    private boolean mHasWindowFocus = false;
-    private final Object mHasWindowFocusLock = new Object();
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.keylistener_layout);
     }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus) {
-        super.onWindowFocusChanged(hasFocus);
-        if (!hasFocus) {
-            Log.w("KeyListenerCtsActivity", "KeyListenerCtsActivity lost window focus");
-        }
-        synchronized(mHasWindowFocusLock) {
-            mHasWindowFocus = hasFocus;
-            mHasWindowFocusLock.notify();
-        }
-    }
-
-    /**
-     * Blocks the calling thread until the {@link KeyListenerCtsActivity} has window focus or the
-     * specified duration (in milliseconds) has passed.
-     */
-    public boolean waitForWindowFocus(long durationMillis) {
-        long elapsedMillis = SystemClock.elapsedRealtime();
-        synchronized(mHasWindowFocusLock) {
-            mHasWindowFocus = hasWindowFocus();
-            while (!mHasWindowFocus && durationMillis > 0) {
-                long newElapsedMillis = SystemClock.elapsedRealtime();
-                durationMillis -= (newElapsedMillis - elapsedMillis);
-                elapsedMillis = newElapsedMillis;
-                if (durationMillis > 0) {
-                    try {
-                        mHasWindowFocusLock.wait(durationMillis);
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-            return mHasWindowFocus;
-        }
-    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index ed0110a..ae8f57e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -47,6 +47,7 @@
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -294,9 +295,9 @@
             .runWithVerifier(new RectVerifier(Color.WHITE, Color.GREEN, new Rect(40, 40, 70, 70)));
     }
 
-    // Note: This test will fail for Skia pipeline, but that is OK.
-    // TODO: delete this test when Skia pipeline is default and modify next test
+    // STOPSHIP: delete this test when Skia pipeline ships as the default and modify next test
     // testSaveLayerUnclippedWithColorFilterSW to run for both HW and SW
+    @Ignore
     @Test
     public void testSaveLayerUnclippedWithColorFilterHW() {
         // verify that HW can draw nested unclipped layers with chained color filters
diff --git a/tests/tests/view/src/android/view/cts/TooltipTest.java b/tests/tests/view/src/android/view/cts/TooltipTest.java
index 1717763..c2c8e87 100644
--- a/tests/tests/view/src/android/view/cts/TooltipTest.java
+++ b/tests/tests/view/src/android/view/cts/TooltipTest.java
@@ -256,9 +256,6 @@
         injectLongClick(mTooltipView);
         assertFalse(hasTooltip(mTooltipView));
 
-        injectLongEnter(mTooltipView);
-        assertFalse(hasTooltip(mTooltipView));
-
         injectLongHoverMove(mTooltipView);
         assertFalse(hasTooltip(mTooltipView));
     }
diff --git a/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java b/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
index 774aadb..955cf7c 100644
--- a/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
+++ b/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
@@ -174,7 +174,7 @@
     }
 
     private void addMovement() {
-        if (mTime >= mLastTime) {
+        if (mTime > mLastTime) {
             MotionEvent ev = MotionEvent.obtain(0L, mTime, MotionEvent.ACTION_MOVE, mPx, mPy, 0);
             mVelocityTracker.addMovement(ev);
             ev.recycle();
@@ -201,9 +201,9 @@
         if (errorVx > tolerance || errorVy > tolerance) {
             fail(String.format("Velocity exceeds tolerance of %6.1f%%: "
                     + "expected vx=%6.1f, vy=%6.1f. "
-                    + "actual vx=%6.1f (%6.1f%%), vy=%6.1f (%6.1f%%)",
+                    + "actual vx=%6.1f (%6.1f%%), vy=%6.1f (%6.1f%%). %s",
                     tolerance * 100.0f, mVx, mVy,
-                    estimatedVx, errorVx * 100.0f, estimatedVy, errorVy * 100.0f));
+                    estimatedVx, errorVx * 100.0f, estimatedVy, errorVy * 100.0f, message));
         }
     }
 
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 831aa15..62537ba 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -149,7 +149,8 @@
         PollingCheck.waitFor(mActivity::hasWindowFocus);
         mResources = mActivity.getResources();
         mMockParent = new MockViewParent(mActivity);
-        assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
+        PollingCheck.waitFor(5 * DateUtils.SECOND_IN_MILLIS, mActivity::hasWindowFocus);
+        assertTrue(mActivity.hasWindowFocus());
     }
 
     @Test
diff --git a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
index 9766fa2..9117925 100644
--- a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
@@ -18,52 +18,13 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.SystemClock;
-import android.util.Log;
 import android.view.cts.R;
 
 public class ViewTestCtsActivity extends Activity {
-    private boolean mHasWindowFocus = false;
-    private final Object mHasWindowFocusLock = new Object();
 
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setContentView(R.layout.view_layout);
     }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus) {
-        super.onWindowFocusChanged(hasFocus);
-        if (!hasFocus) {
-            Log.w("ViewTestCtsActivity", "ViewTestCtsActivity lost window focus");
-        }
-        synchronized(mHasWindowFocusLock) {
-            mHasWindowFocus = hasFocus;
-            mHasWindowFocusLock.notify();
-        }
-    }
-
-    /**
-     * Blocks the calling thread until the {@link ViewTestCtsActivity} has window focus or the
-     * specified duration (in milliseconds) has passed.
-     */
-    public boolean waitForWindowFocus(long durationMillis) {
-        long elapsedMillis = SystemClock.elapsedRealtime();
-        synchronized(mHasWindowFocusLock) {
-            mHasWindowFocus = hasWindowFocus();
-            while (!mHasWindowFocus && durationMillis > 0) {
-                long newElapsedMillis = SystemClock.elapsedRealtime();
-                durationMillis -= (newElapsedMillis - elapsedMillis);
-                elapsedMillis = newElapsedMillis;
-                if (durationMillis > 0) {
-                    try {
-                        mHasWindowFocusLock.wait(durationMillis);
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-            return mHasWindowFocus;
-        }
-    }
 }
diff --git a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
index 21fdd89..ae780fb 100644
--- a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
+++ b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
@@ -227,6 +227,60 @@
 
     @UiThreadTest
     @Test
+    public void testEnabledHandling() {
+        Activity activity = mActivityRule.getActivity();
+
+        View v1 = activity.findViewById(R.id.view1);
+        View v2 = activity.findViewById(R.id.view2);
+        View v3 = activity.findViewById(R.id.view3);
+        View v4 = activity.findViewById(R.id.view4);
+
+        for (View v : new View[]{v1, v2, v3, v4}) v.setFocusable(true);
+
+        assertTrue(v1.requestFocus());
+
+        // disabled view should not be focusable
+        assertTrue(v1.hasFocus());
+        v1.setEnabled(false);
+        assertFalse(v1.hasFocus());
+        v1.requestFocus();
+        assertFalse(v1.hasFocus());
+        v1.setEnabled(true);
+        v1.requestFocus();
+        assertTrue(v1.hasFocus());
+
+        // an enabled view should not take focus if not visible OR not enabled
+        v1.setEnabled(false);
+        v1.setVisibility(View.INVISIBLE);
+        assertFalse(v1.hasFocus());
+        v1.setEnabled(true);
+        v1.requestFocus();
+        assertFalse(v1.hasFocus());
+        v1.setEnabled(false);
+        v1.setVisibility(View.VISIBLE);
+        v1.requestFocus();
+        assertFalse(v1.hasFocus());
+        v1.setEnabled(true);
+        v1.requestFocus();
+        assertTrue(v1.hasFocus());
+
+        // test hasFocusable
+        ViewGroup parent = (ViewGroup) v1.getParent();
+        assertTrue(parent.hasFocusable());
+        for (View v : new View[]{v1, v2, v3, v4}) v.setEnabled(false);
+        assertFalse(v1.isFocused());
+        assertFalse(v2.isFocused());
+        assertFalse(v3.isFocused());
+        assertFalse(v4.isFocused());
+        assertFalse(parent.hasFocusable());
+
+        // a view enabled while nothing has focus should get focus.
+        for (View v : new View[]{v1, v2, v3, v4}) v.setEnabled(true);
+        assertEquals(true, v1.isFocused());
+    }
+
+    @UiThreadTest
+    @Test
     public void testFocusAuto() {
         Activity activity = mActivityRule.getActivity();
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
index ecc3e4f..0fa239d 100644
--- a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
@@ -101,12 +101,26 @@
 
     // Post a string message to main frame and make sure it is received.
     public void testSimpleMessageToMainFrame() throws Throwable {
+        verifyPostMessageToOrigin(Uri.parse(BASE_URI));
+    }
+
+    // Post a string message to main frame passing a wildcard as target origin
+    public void testWildcardOriginMatchesAnything() throws Throwable {
+        verifyPostMessageToOrigin(Uri.parse("*"));
+    }
+
+    // Post a string message to main frame passing an empty string as target origin
+    public void testEmptyStringOriginMatchesAnything() throws Throwable {
+        verifyPostMessageToOrigin(Uri.parse(""));
+    }
+
+    private void verifyPostMessageToOrigin(Uri origin) throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
         loadPage(TITLE_FROM_POST_MESSAGE);
         WebMessage message = new WebMessage(WEBVIEW_MESSAGE);
-        mOnUiThread.postWebMessage(message, Uri.parse(BASE_URI));
+        mOnUiThread.postWebMessage(message, origin);
         waitForTitle(WEBVIEW_MESSAGE);
     }
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index b4be068..a3eabaf 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -27,6 +27,7 @@
 import android.graphics.Color;
 import android.graphics.Picture;
 import android.graphics.Rect;
+import android.graphics.pdf.PdfRenderer;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -2562,7 +2563,8 @@
                     // Called on UI thread
                     @Override
                     public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
-                        savePrintedPage(adapter, descriptor, result);
+                        PageRange[] pageRanges = new PageRange[] {PageRange.ALL_PAGES};
+                        savePrintedPage(adapter, descriptor, pageRanges, result);
                     }
                 });
         try {
@@ -2580,6 +2582,57 @@
         }
     }
 
+    // Verify Print feature can create a PDF file with correct number of pages.
+    public void testPrintingPagesCount() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        String content = "<html><head></head><body>";
+        for (int i = 0; i < 500; ++i) {
+            content += "<br />abcdefghijk<br />";
+        }
+        content += "</body></html>";
+        mOnUiThread.loadDataAndWaitForCompletion(content, "text/html", null);
+        final PrintDocumentAdapter adapter =  mOnUiThread.createPrintDocumentAdapter();
+        printDocumentStart(adapter);
+        PrintAttributes attributes = new PrintAttributes.Builder()
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
+                .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
+                .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
+                .build();
+        final WebViewCtsActivity activity = getActivity();
+        final File file = activity.getFileStreamPath(PRINTER_TEST_FILE);
+        final ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file,
+                ParcelFileDescriptor.parseMode("w"));
+        final FutureTask<Boolean> result =
+                new FutureTask<Boolean>(new Callable<Boolean>() {
+                            public Boolean call() {
+                                return true;
+                            }
+                        });
+        printDocumentLayout(adapter, null, attributes,
+                new LayoutResultCallback() {
+                    // Called on UI thread
+                    @Override
+                    public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+                        PageRange[] pageRanges = new PageRange[] {
+                            new PageRange(1, 1), new PageRange(4, 7)
+                        };
+                        savePrintedPage(adapter, descriptor, pageRanges, result);
+                    }
+                });
+        try {
+            result.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+            assertTrue(file.length() > 0);
+            PdfRenderer renderer = new PdfRenderer(
+                ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
+            assertEquals(5, renderer.getPageCount());
+        } finally {
+            descriptor.close();
+            file.delete();
+        }
+    }
+
     public void testVisualStateCallbackCalled() throws Exception {
         // Check that the visual state callback is called correctly.
         if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -2796,8 +2849,9 @@
     }
 
     private void savePrintedPage(final PrintDocumentAdapter adapter,
-            final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
-        adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
+            final ParcelFileDescriptor descriptor, final PageRange[] pageRanges,
+            final FutureTask<Boolean> result) {
+        adapter.onWrite(pageRanges, descriptor,
                 new CancellationSignal(),
                 new WriteResultCallback() {
                     @Override
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index d311d75..517c149 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -383,6 +383,44 @@
                 android:text="@string/sample_text"
                 android:justificationMode="inter_word" />
 
+            <TextView
+                android:id="@+id/textview_textappearance_attrs1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sample_text"
+                style="@null"
+                android:textAppearance="@style/TextAppearance.Xml1" />
+
+            <TextView
+                android:id="@+id/textview_textappearance_attrs2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sample_text"
+                style="@null"
+                android:textAppearance="@style/TextAppearance.Xml2" />
+
+            <TextView
+                android:id="@+id/textview_textappearance_attrs3"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sample_text"
+                android:textAppearance="@style/TextAppearance.Xml2"
+                style="@style/TextAppearance.Xml3" />
+
+            <TextView
+                android:id="@+id/textview_textappearance_attrs4"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sample_text"
+                style="@style/TextAppearance.Xml3" />
+
+            <TextView
+                android:id="@+id/textview_textappearance_attrs_allcaps_password"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sample_text"
+                style="@style/AllCapsPassword" />
+
         </LinearLayout>
 
 </ScrollView>
diff --git a/tests/tests/widget/res/menu/popup_menu.xml b/tests/tests/widget/res/menu/popup_menu.xml
index 29daad0..a2653b4 100644
--- a/tests/tests/widget/res/menu/popup_menu.xml
+++ b/tests/tests/widget/res/menu/popup_menu.xml
@@ -18,12 +18,14 @@
           android:title="@string/popup_menu_highlight"
           android:contentDescription="@string/popup_menu_highlight_description"
           android:tooltipText="@string/popup_menu_highlight_tooltip" />
-    <item android:id="@+id/action_edit"
-          android:title="@string/popup_menu_edit"
-          android:contentDescription="@string/popup_menu_edit_description"
-          android:tooltipText="@string/popup_menu_edit_tooltip" />
-    <item android:id="@+id/action_delete"
-          android:title="@string/popup_menu_delete" />
+    <group android:id="@+id/group_test2">
+        <item android:id="@+id/action_edit"
+              android:title="@string/popup_menu_edit"
+              android:contentDescription="@string/popup_menu_edit_description"
+              android:tooltipText="@string/popup_menu_edit_tooltip" />
+        <item android:id="@+id/action_delete"
+              android:title="@string/popup_menu_delete" />
+    </group>
     <item android:id="@+id/action_ignore"
           android:title="@string/popup_menu_ignore" />
     <item android:id="@+id/action_share"
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index a47f169..8d44c7a 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -109,6 +109,43 @@
         <item name="android:textStyle">normal</item>
     </style>
 
+    <style name="TextAppearance.Xml1">
+        <item name="android:textSize">22px</item>
+        <item name="android:typeface">sans</item>
+        <item name="android:textStyle">italic</item>
+        <item name="android:textAllCaps">true</item>
+        <item name="android:letterSpacing">2.4</item>
+        <item name="android:fontFeatureSettings">smcp</item>
+    </style>
+
+    <style name="TextAppearance.Xml2">
+        <item name="android:fontFamily">monospace</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:shadowColor">@drawable/red</item>
+        <item name="android:shadowDx">10.3</item>
+        <item name="android:shadowDy">0.5</item>
+        <item name="android:shadowRadius">3.3</item>
+        <item name="android:elegantTextHeight">true</item>
+    </style>
+
+    <style name="TextAppearance.Xml3">
+        <item name="android:textSize">32px</item>
+        <item name="android:fontFamily">serif</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:letterSpacing">2.6</item>
+        <item name="android:shadowColor">@drawable/blue</item>
+        <item name="android:shadowDx">1.3</item>
+        <item name="android:shadowDy">10.5</item>
+        <item name="android:shadowRadius">5.3</item>
+        <item name="android:elegantTextHeight">false</item>
+    </style>
+
+    <style name="AllCapsPassword">
+        <item name="android:textAllCaps">true</item>
+        <item name="android:password">true</item>
+    </style>
+
     <style name="TestEnum1">
         <item name="testEnum">val1</item>
     </style>
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 5ce73a8..0f89105 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -40,6 +40,7 @@
 import android.view.SubMenu;
 import android.view.View;
 import android.widget.EditText;
+import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.PopupMenu;
 
@@ -303,6 +304,36 @@
         }
     }
 
+    @Test
+    public void testGroupDividerEnabledAPI() throws Throwable {
+        testGroupDivider(false);
+        testGroupDivider(true);
+    }
+
+    private void testGroupDivider(boolean groupDividerEnabled) throws Throwable {
+        mBuilder = new Builder().withGroupDivider(groupDividerEnabled);
+        WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, mBuilder::show, true);
+
+        Menu menu = mPopupMenu.getMenu();
+        ListView menuItemList = mPopupMenu.getMenuListView();
+
+        for (int i = 0; i < menuItemList.getCount(); i++) {
+            final int currGroupId = menu.getItem(i).getGroupId();
+            final int prevGroupId =
+                    i - 1 >= 0 ? menu.getItem(i - 1).getGroupId() : currGroupId;
+            View itemView = menuItemList.getChildAt(i);
+            ImageView groupDivider = itemView.findViewById(com.android.internal.R.id.group_divider);
+
+            if (!groupDividerEnabled || currGroupId == prevGroupId) {
+                assertEquals(groupDivider.getVisibility(), View.GONE);
+            } else {
+                assertEquals(groupDivider.getVisibility(), View.VISIBLE);
+            }
+        }
+
+        teardown();
+    }
+
     /**
      * Inner helper class to configure an instance of {@link PopupMenu} for the specific test.
      * The main reason for its existence is that once a popup menu is shown with the show() method,
@@ -328,6 +359,8 @@
 
         private View mAnchor;
 
+        private boolean mGroupDividerEnabled = false;
+
         public Builder withMenuItemClickListener() {
             mHasMenuItemClickListener = true;
             return this;
@@ -360,6 +393,11 @@
             return this;
         }
 
+        public Builder withGroupDivider(boolean groupDividerEnabled) {
+            mGroupDividerEnabled = groupDividerEnabled;
+            return this;
+        }
+
         private void configure() {
             mAnchor = mActivity.findViewById(R.id.anchor_middle_left);
             if (!mUseCustomGravity && !mUseCustomPopupResource) {
@@ -390,6 +428,10 @@
                 mOnDismissListener = mock(PopupMenu.OnDismissListener.class);
                 mPopupMenu.setOnDismissListener(mOnDismissListener);
             }
+
+            if (mGroupDividerEnabled) {
+                mPopupMenu.getMenu().setGroupDividerEnabled(true);
+            }
         }
 
         public void show() {
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 8b816fe..6e02824 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -4409,6 +4409,66 @@
         assertEquals(null, mTextView.getTypeface());
     }
 
+    @Test
+    public void testXmlTextAppearance() {
+        mTextView = findTextView(R.id.textview_textappearance_attrs1);
+        assertEquals(22f, mTextView.getTextSize(), 0.01f);
+        Typeface italicSans = Typeface.create(Typeface.SANS_SERIF, Typeface.ITALIC);
+        assertEquals(italicSans, mTextView.getTypeface());
+        assertEquals(Typeface.ITALIC, mTextView.getTypeface().getStyle());
+        assertTrue(mTextView.isAllCaps());
+        assertEquals(2.4f, mTextView.getLetterSpacing(), 0.01f);
+        assertEquals("smcp", mTextView.getFontFeatureSettings());
+
+        mTextView = findTextView(R.id.textview_textappearance_attrs2);
+        assertEquals(Typeface.MONOSPACE, mTextView.getTypeface());
+        assertEquals(mActivity.getResources().getColor(R.drawable.red),
+                mTextView.getShadowColor());
+        assertEquals(10.3f, mTextView.getShadowDx(), 0.01f);
+        assertEquals(0.5f, mTextView.getShadowDy(), 0.01f);
+        assertEquals(3.3f, mTextView.getShadowRadius(), 0.01f);
+        assertTrue(mTextView.isElegantTextHeight());
+
+        // This TextView has both a TextAppearance and a style, so the style should override.
+        mTextView = findTextView(R.id.textview_textappearance_attrs3);
+        assertEquals(32f, mTextView.getTextSize(), 0.01f);
+        Typeface boldSerif = Typeface.create(Typeface.SERIF, Typeface.BOLD);
+        assertEquals(boldSerif, mTextView.getTypeface());
+        assertEquals(Typeface.BOLD, mTextView.getTypeface().getStyle());
+        assertFalse(mTextView.isAllCaps());
+        assertEquals(2.6f, mTextView.getLetterSpacing(), 0.01f);
+        assertEquals(mActivity.getResources().getColor(R.drawable.blue),
+                mTextView.getShadowColor());
+        assertEquals(1.3f, mTextView.getShadowDx(), 0.01f);
+        assertEquals(10.5f, mTextView.getShadowDy(), 0.01f);
+        assertEquals(5.3f, mTextView.getShadowRadius(), 0.01f);
+        assertFalse(mTextView.isElegantTextHeight());
+
+        // This TextView has no TextAppearance and has a style, so the style should be applied.
+        mTextView = findTextView(R.id.textview_textappearance_attrs4);
+        assertEquals(32f, mTextView.getTextSize(), 0.01f);
+        assertEquals(boldSerif, mTextView.getTypeface());
+        assertEquals(Typeface.BOLD, mTextView.getTypeface().getStyle());
+        assertFalse(mTextView.isAllCaps());
+        assertEquals(2.6f, mTextView.getLetterSpacing(), 0.01f);
+        assertEquals(mActivity.getResources().getColor(R.drawable.blue),
+                mTextView.getShadowColor());
+        assertEquals(1.3f, mTextView.getShadowDx(), 0.01f);
+        assertEquals(10.5f, mTextView.getShadowDy(), 0.01f);
+        assertEquals(5.3f, mTextView.getShadowRadius(), 0.01f);
+        assertFalse(mTextView.isElegantTextHeight());
+
+        // Note: text, link and hint colors can't be tested due to the default style overriding
+        // values b/63923542
+    }
+
+    @Test
+    public void testAttributeReading_allCapsAndPassword() {
+        // This TextView has all caps & password, therefore all caps should be ignored.
+        mTextView = findTextView(R.id.textview_textappearance_attrs_allcaps_password);
+        assertFalse(mTextView.isAllCaps());
+    }
+
     @UiThreadTest
     @Test
     public void testAccessCompoundDrawableTint() {
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
new file mode 100644
index 0000000..820f1bb
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	compatibility-device-util \
+	android-support-test \
+	legacy-android-test
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PREBUILT_JNI_LIBS_arm := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_arm64 := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_mips := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_mips64 := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_x86 := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_x86_64 := wrap.sh
+
+LOCAL_PACKAGE_NAME := CtsWrapWrapDebugMallocDebugTestCases
+LOCAL_MANIFEST_FILE := AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/AndroidManifest.xml b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidManifest.xml
new file mode 100644
index 0000000..a359f17
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.wrap.wrap_debug_malloc_debug.cts">
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+        <meta-data android:name="android.wrap.cts.expext_env" android:value="true" />
+        <activity android:name="android.wrap.WrapActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="CTS tests for wrap.sh"
+        android:targetPackage="android.wrap.wrap_debug_malloc_debug.cts" >
+    </instrumentation>
+</manifest>
+
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/AndroidTest.xml b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidTest.xml
new file mode 100644
index 0000000..ef5b71e
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Debug Wrap (Malloc Debug) test cases">
+    <option name="config-descriptor:metadata" key="component" value="art" />
+    <option name="not-shardable" value="true" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsWrapWrapDebugMallocDebugTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.wrap.wrap_debug_malloc_debug.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/wrap.sh b/tests/tests/wrap/wrap_debug_malloc_debug/wrap.sh
new file mode 100755
index 0000000..f00a554
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/wrap.sh
@@ -0,0 +1,15 @@
+#!/system/bin/sh
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+LIBC_DEBUG_MALLOC_OPTIONS=backtrace=1 WRAP_PROPERTY=test $@
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 5fed5b4..1008b67 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -121,6 +121,12 @@
     <!-- b/36686383 -->
     <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testANR" />
 
+    <!-- b/33090965 -->
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0320x0180" />
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0640x0360" />
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720" />
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080" />
+
     <!-- b/37482372 -->
     <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowHistoryPreservePortraitTest" />
     <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowInOutPortraitTest" />
@@ -165,6 +171,9 @@
     <option name="compatibility:exclude-filter" value="x86_64 CtsMediaBitstreamsTestCases" />
     <option name="compatibility:exclude-filter" value="mips64 CtsMediaBitstreamsTestCases" />
 
+    <!-- b/38280830 -->
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testVp8Goog0Perf1280x0720" />
+
     <!-- b/38420898 -->
     <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelMultiChannel" />
     <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyGyroMultiChannel" />
@@ -189,7 +198,4 @@
     <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRegisterMultipleChannels" />
     <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testReconfigure" />
 
-    <!-- b/63566721 -->
-    <option name="compatibility:exclude-filter" value="CtsWrapWrapDebugTestCases android.wrap.cts.WrapTest" />
-
 </configuration>
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 672ebe9..74118bd 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -25,7 +25,6 @@
 LOCAL_MODULE_CLASS := JAVA_LIBRARIES
 LOCAL_MODULE_TAGS := optional
 LOCAL_JAVA_LIBRARIES := junit
--include cts/error_prone_rules_tests.mk
 include $(BUILD_JAVA_LIBRARY)
 
 cts-tf-dalvik-lib.jack := $(full_classes_jack)