Merge "CTS/STS test for Android Security b/35644510" into nyc-mr2-dev am: b6f8507a88 am: 2f6113bbd3
am: 265a7c0234

Change-Id: I02dff846aafd787ad0b324092f147129d666536d
diff --git a/apps/CameraITS/build/scripts/gpylint_rcfile b/apps/CameraITS/build/scripts/gpylint_rcfile
index 43d3dbc..37f43f7 100644
--- a/apps/CameraITS/build/scripts/gpylint_rcfile
+++ b/apps/CameraITS/build/scripts/gpylint_rcfile
@@ -279,7 +279,7 @@
 
 # Number of spaces of indent required when the last token on the preceding line
 # is an open (, [, or {.
-indent-after-paren=4
+indent-after-paren=8
 
 # Minimum number of spaces between the end of a line and an inline comment.
 min-comment-space=2
diff --git a/apps/CameraITS/tests/rolling_shutter_skew/RollingShutterSkew.pdf b/apps/CameraITS/tests/rolling_shutter_skew/RollingShutterSkew.pdf
new file mode 100644
index 0000000..1a6c30a
--- /dev/null
+++ b/apps/CameraITS/tests/rolling_shutter_skew/RollingShutterSkew.pdf
Binary files differ
diff --git a/apps/CameraITS/tests/rolling_shutter_skew/test_rolling_shutter_skew.py b/apps/CameraITS/tests/rolling_shutter_skew/test_rolling_shutter_skew.py
new file mode 100644
index 0000000..824c180
--- /dev/null
+++ b/apps/CameraITS/tests/rolling_shutter_skew/test_rolling_shutter_skew.py
@@ -0,0 +1,675 @@
+"""Experimentally determines a camera's rolling shutter skew.
+
+See the accompanying PDF for instructions on how to use this test.
+"""
+from __future__ import division
+from __future__ import print_function
+
+import argparse
+import glob
+import math
+import os
+import sys
+import tempfile
+
+import cv2
+import its.caps
+import its.device
+import its.image
+import its.objects
+import numpy as np
+
+DEBUG = False
+
+# Constants for which direction the camera is facing.
+FACING_FRONT = 0
+FACING_BACK = 1
+FACING_EXTERNAL = 2
+
+# Camera capture defaults.
+FPS = 30
+WIDTH = 640
+HEIGHT = 480
+TEST_LENGTH = 1
+
+# Each circle in a cluster must be within this many pixels of some other circle
+# in the cluster.
+CLUSTER_DISTANCE = 50.0 / HEIGHT
+# A cluster must consist of at least this percentage of the total contours for
+# it to be allowed into the computation.
+MAJORITY_THRESHOLD = 0.7
+
+# Constants to make sure the slope of the fitted line is reasonable.
+SLOPE_MIN_THRESHOLD = 0.5
+SLOPE_MAX_THRESHOLD = 1.5
+
+# To improve readability of unit conversions.
+SEC_TO_NSEC = float(10**9)
+MSEC_TO_NSEC = float(10**6)
+NSEC_TO_MSEC = 1.0 / float(10**6)
+
+
+class RollingShutterArgumentParser(object):
+    """Parses command line arguments for the rolling shutter test."""
+
+    def __init__(self):
+        self.__parser = argparse.ArgumentParser(
+                description='Run rolling shutter test')
+        self.__parser.add_argument(
+                '-d', '--debug',
+                action='store_true',
+                help='print and write data useful for debugging')
+        self.__parser.add_argument(
+                '-f', '--fps',
+                type=int,
+                help='FPS to capture with during the test (defaults to 30)')
+        self.__parser.add_argument(
+                '-i', '--img_size',
+                help=('comma-separated dimensions of captured images (defaults '
+                      'to 640x480). Example: --img_size=<width>,<height>'))
+        self.__parser.add_argument(
+                '-l', '--led_time',
+                type=float,
+                required=True,
+                help=('how many milliseconds each column of the LED array is '
+                      'lit for'))
+        self.__parser.add_argument(
+                '-p', '--panel_distance',
+                type=float,
+                help='how far the LED panel is from the camera (in meters)')
+        self.__parser.add_argument(
+                '-r', '--read_dir',
+                help=('read existing test data from specified directory.  If '
+                      'not specified, new test data is collected from the '
+                      'device\'s camera)'))
+        self.__parser.add_argument(
+                '--device_id',
+                help=('device ID for device being tested (can also use '
+                      '\'device=<DEVICE ID>\')'))
+        self.__parser.add_argument(
+                '-t', '--test_length',
+                type=int,
+                help=('how many seconds the test should run for (defaults to 1 '
+                      'second)'))
+        self.__parser.add_argument(
+                '-o', '--debug_dir',
+                help=('write debugging information in a folder in the '
+                      'specified directory.  Otherwise, the system\'s default '
+                      'location for temporary folders is used.  --debug must '
+                      'be specified along with this argument.'))
+
+    def parse_args(self):
+        """Returns object containing parsed values from the command line."""
+        # Don't show argparse the 'device' flag, since it's in a different
+        # format than the others (to maintain CameraITS conventions) and it will
+        # complain.
+        filtered_args = [arg for arg in sys.argv[1:] if 'device=' not in arg]
+        args = self.__parser.parse_args(filtered_args)
+        if args.device_id:
+            # If argparse format is used, convert it to a format its.device can
+            # use later on.
+            sys.argv.append('device=%s' % args.device_id)
+        return args
+
+
+def main():
+    global DEBUG
+    global CLUSTER_DISTANCE
+
+    parser = RollingShutterArgumentParser()
+    args = parser.parse_args()
+
+    DEBUG = args.debug
+    if not DEBUG and args.debug_dir:
+        print('argument --debug_dir requires --debug', file=sys.stderr)
+        sys.exit()
+
+    if args.read_dir is None:
+        # Collect new data.
+        raw_caps, reported_skew = collect_data(args)
+        frames = [its.image.convert_capture_to_rgb_image(c) for c in raw_caps]
+    else:
+        # Load existing data.
+        frames, reported_skew = load_data(args.read_dir)
+
+    # Make the cluster distance relative to the height of the image.
+    (frame_h, _, _) = frames[0].shape
+    CLUSTER_DISTANCE = frame_h * CLUSTER_DISTANCE
+    debug_print('Setting cluster distance to %spx.' % CLUSTER_DISTANCE)
+
+    if DEBUG:
+        debug_dir = setup_debug_dir(args.debug_dir)
+        # Write raw frames.
+        for i, img in enumerate(frames):
+            its.image.write_image(img, '%s/raw/%03d.png' % (debug_dir, i))
+    else:
+        debug_dir = None
+
+    avg_shutter_skew, num_frames_used = find_average_shutter_skew(
+            frames, args.led_time, debug_dir)
+    if debug_dir:
+        # Write the reported skew with the raw images, so the directory can also
+        # be used to read from.
+        with open(debug_dir + '/raw/reported_skew.txt', 'w') as f:
+            f.write('%sms\n' % reported_skew)
+
+    if avg_shutter_skew is None:
+        print('Could not find usable frames.')
+    else:
+        print('Device reported shutter skew of %sms.' % reported_skew)
+        print('Measured shutter skew is %sms (averaged over %s frames).' %
+              (avg_shutter_skew, num_frames_used))
+
+
+def collect_data(args):
+    """Capture a new set of frames from the device's camera.
+
+    Args:
+        args: Parsed command line arguments.
+
+    Returns:
+        A list of RGB images as numpy arrays.
+    """
+    fps = args.fps if args.fps else FPS
+    if args.img_size:
+        w, h = map(int, args.img_size.split(','))
+    else:
+        w, h = WIDTH, HEIGHT
+    test_length = args.test_length if args.test_length else TEST_LENGTH
+
+    with its.device.ItsSession() as cam:
+        props = cam.get_camera_properties()
+        its.caps.skip_unless(its.caps.manual_sensor(props))
+        facing = props['android.lens.facing']
+        if facing != FACING_FRONT and facing != FACING_BACK:
+            print('Unknown lens facing %s' % facing)
+            assert 0
+
+        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)
+        req['android.control.aeTargetFpsRange'] = [fps, fps]
+
+        # Convert from milliseconds to nanoseconds.  We only want enough
+        # exposure time to saturate approximately one column.
+        exposure_time = (args.led_time / 2.0) * MSEC_TO_NSEC
+        print('Using exposure time of %sns.' % exposure_time)
+        req['android.sensor.exposureTime'] = exposure_time
+        req["android.sensor.frameDuration"] = int(SEC_TO_NSEC / fps);
+
+        if args.panel_distance is not None:
+            # Convert meters to diopters and use that for the focus distance.
+            req['android.lens.focusDistance'] = 1 / args.panel_distance
+        print('Starting capture')
+        raw_caps = cam.do_capture([req]*fps*test_length, fmt)
+        print('Finished capture')
+
+        # Convert from nanoseconds to milliseconds.
+        shutter_skews = {c['metadata']['android.sensor.rollingShutterSkew'] *
+                          NSEC_TO_MSEC for c in raw_caps}
+        # All frames should have same rolling shutter skew.
+        assert len(shutter_skews) == 1
+        shutter_skew = list(shutter_skews)[0]
+
+        return raw_caps, shutter_skew
+
+
+def load_data(dir_name):
+    """Reads camera frame data from an existing directory.
+
+    Args:
+        dir_name: Name of the directory to read data from.
+
+    Returns:
+        A list of RGB images as numpy arrays.
+    """
+    frame_files = glob.glob('%s/*.png' % dir_name)
+    frames = []
+    for frame_file in sorted(frame_files):
+        frames.append(its.image.load_rgb_image(frame_file))
+    with open('%s/reported_skew.txt' % dir_name, 'r') as f:
+        reported_skew = f.readline()[:-2]  # Strip off 'ms' suffix
+    return frames, reported_skew
+
+
+def find_average_shutter_skew(frames, led_time, debug_dir=None):
+    """Finds the average shutter skew using the given frames.
+
+    Frames without enough information will be discarded from the average to
+    improve overall accuracy.
+
+    Args:
+        frames:    List of RGB images from the camera being tested.
+        led_time:  How long a single LED column is lit for (in milliseconds).
+        debug_dir: (optional) Directory to write debugging information to.
+
+    Returns:
+        The average calculated shutter skew and the number of frames used to
+        calculate the average.
+    """
+    avg_shutter_skew = 0.0
+    avg_slope = 0.0
+    weight = 0.0
+    num_frames_used = 0
+
+    for i, frame in enumerate(frames):
+        debug_print('------------------------')
+        debug_print('| PROCESSING FRAME %03d |' % i)
+        debug_print('------------------------')
+        shutter_skew, confidence, slope = calculate_shutter_skew(
+                frame, led_time, i, debug_dir=debug_dir)
+        if shutter_skew is None:
+            debug_print('Skipped frame.')
+        else:
+            debug_print('Shutter skew is %sms (confidence: %s).' %
+                        (shutter_skew, confidence))
+            # Use the confidence to weight the average.
+            avg_shutter_skew += shutter_skew * confidence
+            avg_slope += slope * confidence
+            weight += confidence
+            num_frames_used += 1
+
+    debug_print('\n')
+    if num_frames_used == 0:
+        return None, None
+    else:
+        avg_shutter_skew /= weight
+        avg_slope /= weight
+        slope_err_str = ('The average slope of the fitted line was too %s '
+                         'to get an accurate measurement (slope was %s).  '
+                         'Try making the LED panel %s.')
+        if avg_slope < SLOPE_MIN_THRESHOLD:
+            print(slope_err_str % ('flat', avg_slope, 'slower'),
+                  file=sys.stderr)
+        elif avg_slope > SLOPE_MAX_THRESHOLD:
+            print(slope_err_str % ('steep', avg_slope, 'faster'),
+                  file=sys.stderr)
+        return avg_shutter_skew, num_frames_used
+
+
+def calculate_shutter_skew(frame, led_time, frame_num=None, debug_dir=None):
+    """Calculates the shutter skew of the camera being used for this test.
+
+    Args:
+        frame:     A single RGB image captured by the camera being tested.
+        led_time:  How long a single LED column is lit for (in milliseconds).
+        frame_num: (optional) Number of the given frame.
+        debug_dir: (optional) Directory to write debugging information to.
+
+    Returns:
+        The shutter skew (in milliseconds), the confidence in the accuracy of
+        the measurement (useful for weighting averages), and the slope of the
+        fitted line.
+    """
+    contours, scratch_img, contour_img, mono_img = find_contours(frame.copy())
+    if debug_dir is not None:
+        cv2.imwrite('%s/contour/%03d.png' % (debug_dir, frame_num), contour_img)
+        cv2.imwrite('%s/mono/%03d.png' % (debug_dir, frame_num), mono_img)
+
+    largest_cluster, cluster_percentage = find_largest_cluster(contours,
+                                                               scratch_img)
+    if largest_cluster is None:
+        debug_print('No majority cluster found.')
+        return None, None, None
+    elif len(largest_cluster) <= 1:
+        debug_print('Majority cluster was too small.')
+        return None, None, None
+    debug_print('%s points in the largest cluster.' % len(largest_cluster))
+
+    np_cluster = np.array([[c.x, c.y] for c in largest_cluster])
+    [vx], [vy], [x0], [y0] = cv2.fitLine(np_cluster, cv2.cv.CV_DIST_L2,
+                                         0, 0.01, 0.01)
+    slope = vy / vx
+    debug_print('Slope is %s.' % slope)
+    (frame_h, frame_w, _) = frame.shape
+    # Draw line onto scratch frame.
+    pt1 = tuple(map(int, (x0 - vx * 1000, y0 - vy * 1000)))
+    pt2 = tuple(map(int, (x0 + vx * 1000, y0 + vy * 1000)))
+    cv2.line(scratch_img, pt1, pt2, (0, 255, 255), thickness=3)
+
+    # We only need the width of the cluster.
+    _, _, cluster_w, _ = find_cluster_bounding_rect(largest_cluster,
+                                                    scratch_img)
+
+    num_columns = find_num_columns_spanned(largest_cluster)
+    debug_print('%s columns spanned by cluster.' % num_columns)
+    # How long it takes for a column to move from the left of the bounding
+    # rectangle to the right.
+    left_to_right_time = led_time * num_columns
+    milliseconds_per_x_pixel = left_to_right_time / cluster_w
+    # The distance between the line's intersection at the top of the frame and
+    # the intersection at the bottom.
+    x_range = frame_h / slope
+    shutter_skew = milliseconds_per_x_pixel * x_range
+    # If the aspect ratio is different from 4:3 (the aspect ratio of the actual
+    # sensor), we need to correct, because it will be cropped.
+    shutter_skew *= (float(frame_w) / float(frame_h)) / (4.0 / 3.0)
+
+    if debug_dir is not None:
+        cv2.imwrite('%s/scratch/%03d.png' % (debug_dir, frame_num),
+                    scratch_img)
+
+    return shutter_skew, cluster_percentage, slope
+
+
+def find_contours(img):
+    """Finds contours in the given image.
+
+    Args:
+        img: Image in Android camera RGB format.
+
+    Returns:
+        OpenCV-formatted contours, the original image in OpenCV format, a
+        thresholded image with the contours drawn on, and a grayscale version of
+        the image.
+    """
+    # Convert to format OpenCV can work with (BGR ordering with byte-ranged
+    # values).
+    img *= 255
+    img = img.astype(np.uint8)
+    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
+
+    # Since the LED colors for the panel we're using are red, we can get better
+    # contours for the LEDs if we ignore the green and blue channels.  This also
+    # makes it so we don't pick up the blue control screen of the LED panel.
+    red_img = img[:, :, 2]
+    _, thresh = cv2.threshold(red_img, 0, 255, cv2.THRESH_BINARY +
+                              cv2.THRESH_OTSU)
+
+    # Remove noise before finding contours by eroding the thresholded image and
+    # then re-dilating it.  The size of the kernel represents how many
+    # neighboring pixels to consider for the result of a single pixel.
+    kernel = np.ones((3, 3), np.uint8)
+    opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
+
+    if DEBUG:
+        # Need to convert it back to BGR if we want to draw colored contours.
+        contour_img = cv2.cvtColor(opening, cv2.COLOR_GRAY2BGR)
+    else:
+        contour_img = None
+    contours, _ = cv2.findContours(opening,
+                                   cv2.cv.CV_RETR_EXTERNAL,
+                                   cv2.cv.CV_CHAIN_APPROX_NONE)
+    if DEBUG:
+        cv2.drawContours(contour_img, contours, -1, (0, 0, 255), thickness=2)
+    return contours, img, contour_img, red_img
+
+
+def convert_to_circles(contours):
+    """Converts given contours into circle objects.
+
+    Args:
+        contours: Contours generated by OpenCV.
+
+    Returns:
+        A list of circles.
+    """
+
+    class Circle(object):
+        """Holds data to uniquely define a circle."""
+
+        def __init__(self, contour):
+            self.x = int(np.mean(contour[:, 0, 0]))
+            self.y = int(np.mean(contour[:, 0, 1]))
+            # Get diameters of each axis then half it.
+            x_r = (np.max(contour[:, 0, 0]) - np.min(contour[:, 0, 0])) / 2.0
+            y_r = (np.max(contour[:, 0, 1]) - np.min(contour[:, 0, 1])) / 2.0
+            # Average x radius and y radius to get the approximate radius for
+            # the given contour.
+            self.r = (x_r + y_r) / 2.0
+            assert self.r > 0.0
+
+        def distance_to(self, other):
+            return (math.sqrt((other.x - self.x)**2 + (other.y - self.y)**2) -
+                    self.r - other.r)
+
+        def intersects(self, other):
+            return self.distance_to(other) <= 0.0
+
+    return list(map(Circle, contours))
+
+
+def find_largest_cluster(contours, frame):
+    """Finds the largest cluster in the given contours.
+
+    Args:
+        contours: Contours generated by OpenCV.
+        frame:    For drawing debugging information onto.
+
+    Returns:
+        The cluster with the most contours in it and the percentage of all
+        contours that the cluster contains.
+    """
+    clusters = proximity_clusters(contours)
+
+    if not clusters:
+        return None, None  # No clusters found.
+
+    largest_cluster = max(clusters, key=len)
+    cluster_percentage = len(largest_cluster) / len(contours)
+
+    if cluster_percentage < MAJORITY_THRESHOLD:
+        return None, None
+
+    if DEBUG:
+        # Draw largest cluster on scratch frame.
+        for circle in largest_cluster:
+            cv2.circle(frame, (int(circle.x), int(circle.y)), int(circle.r),
+                       (0, 255, 0), thickness=2)
+
+    return largest_cluster, cluster_percentage
+
+
+def proximity_clusters(contours):
+    """Sorts the given contours into groups by distance.
+
+    Converts every given contour to a circle and clusters by adding a circle to
+    a cluster only if it is close to at least one other circle in the cluster.
+
+    TODO: Make algorithm faster (currently O(n**2)).
+
+    Args:
+        contours: Contours generated by OpenCV.
+
+    Returns:
+        A list of clusters, where each cluster is a list of the circles
+        contained in the cluster.
+    """
+    circles = convert_to_circles(contours)
+
+    # Use disjoint-set data structure to store assignments.  Start every point
+    # in their own cluster.
+    cluster_assignments = [-1 for i in range(len(circles))]
+
+    def get_canonical_index(i):
+        if cluster_assignments[i] >= 0:
+            index = get_canonical_index(cluster_assignments[i])
+            # Collapse tree for better runtime.
+            cluster_assignments[i] = index
+            return index
+        else:
+            return i
+
+    def get_cluster_size(i):
+        return -cluster_assignments[get_canonical_index(i)]
+
+    for i, curr in enumerate(circles):
+        close_circles = [j for j, p in enumerate(circles) if i != j and
+                         curr.distance_to(p) < CLUSTER_DISTANCE]
+        if close_circles:
+            # Note: largest_cluster is an index into cluster_assignments.
+            largest_cluster = min(close_circles, key=get_cluster_size)
+            largest_size = get_cluster_size(largest_cluster)
+            curr_index = get_canonical_index(i)
+            curr_size = get_cluster_size(i)
+            if largest_size > curr_size:
+                # largest_cluster is larger than us.
+                target_index = get_canonical_index(largest_cluster)
+                # Add our cluster size to the bigger one.
+                cluster_assignments[target_index] -= curr_size
+                # Reroute our group to the bigger one.
+                cluster_assignments[curr_index] = target_index
+            else:
+                # We're the largest (or equal to the largest) cluster.  Reroute
+                # all groups to us.
+                for j in close_circles:
+                    smaller_size = get_cluster_size(j)
+                    smaller_index = get_canonical_index(j)
+                    if smaller_index != curr_index:
+                        # We only want to modify clusters that aren't already in
+                        # the current one.
+
+                        # Add the smaller cluster's size to ours.
+                        cluster_assignments[curr_index] -= smaller_size
+                        # Reroute their group to us.
+                        cluster_assignments[smaller_index] = curr_index
+
+    # Convert assignments list into list of clusters.
+    clusters_dict = {}
+    for i in range(len(cluster_assignments)):
+        canonical_index = get_canonical_index(i)
+        if canonical_index not in clusters_dict:
+            clusters_dict[canonical_index] = []
+        clusters_dict[canonical_index].append(circles[i])
+    return clusters_dict.values()
+
+
+def find_cluster_bounding_rect(cluster, scratch_frame):
+    """Finds the minimum rectangle that bounds the given cluster.
+
+    The bounding rectangle will always be axis-aligned.
+
+    Args:
+        cluster:       Cluster being used to find the bounding rectangle.
+        scratch_frame: Image that rectangle is drawn onto for debugging
+                       purposes.
+
+    Returns:
+        The leftmost and topmost x and y coordinates, respectively, along with
+        the width and height of the rectangle.
+    """
+    avg_distance = find_average_neighbor_distance(cluster)
+    debug_print('Average distance between points in largest cluster is %s '
+                'pixels.' % avg_distance)
+
+    c_x = min(cluster, key=lambda c: c.x - c.r)
+    c_y = min(cluster, key=lambda c: c.y - c.r)
+    c_w = max(cluster, key=lambda c: c.x + c.r)
+    c_h = max(cluster, key=lambda c: c.y + c.r)
+
+    x = c_x.x - c_x.r - avg_distance
+    y = c_y.y - c_y.r - avg_distance
+    w = (c_w.x + c_w.r + avg_distance) - x
+    h = (c_h.y + c_h.r + avg_distance) - y
+
+    if DEBUG:
+        points = np.array([[x, y], [x + w, y], [x + w, y + h], [x, y + h]],
+                          np.int32)
+        cv2.polylines(scratch_frame, [points], True, (255, 0, 0), thickness=2)
+
+    return x, y, w, h
+
+
+def find_average_neighbor_distance(cluster):
+    """Finds the average distance between every circle and its closest neighbor.
+
+    Args:
+        cluster: List of circles
+
+    Returns:
+        The average distance.
+    """
+    avg_distance = 0.0
+    for a in cluster:
+        closest_point = None
+        closest_dist = None
+        for b in cluster:
+            if a is b:
+                continue
+            curr_dist = a.distance_to(b)
+            if closest_point is None or curr_dist < closest_dist:
+                closest_point = b
+                closest_dist = curr_dist
+        avg_distance += closest_dist
+    avg_distance /= len(cluster)
+    return avg_distance
+
+
+def find_num_columns_spanned(circles):
+    """Finds how many columns of the LED panel are spanned by the given circles.
+
+    Args:
+        circles: List of circles (assumed to be from the LED panel).
+
+    Returns:
+        The number of columns spanned.
+    """
+    if not circles:
+        return 0
+
+    def x_intersects(c_a, c_b):
+        return abs(c_a.x - c_b.x) < (c_a.r + c_b.r)
+
+    circles = sorted(circles, key=lambda c: c.x)
+    last_circle = circles[0]
+    num_columns = 1
+    for circle in circles[1:]:
+        if not x_intersects(circle, last_circle):
+            last_circle = circle
+            num_columns += 1
+
+    return num_columns
+
+
+def setup_debug_dir(dir_name=None):
+    """Creates a debug directory and required subdirectories.
+
+    Each subdirectory contains images from a different step in the process.
+
+    Args:
+        dir_name: The directory to create.  If none is specified, a temp
+        directory is created.
+
+    Returns:
+        The name of the directory that is used.
+    """
+    if dir_name is None:
+        dir_name = tempfile.mkdtemp()
+    else:
+        force_mkdir(dir_name)
+    print('Saving debugging files to "%s"' % dir_name)
+    # For original captured images.
+    force_mkdir(dir_name + '/raw', clean=True)
+    # For monochrome images.
+    force_mkdir(dir_name + '/mono', clean=True)
+    # For contours generated from monochrome images.
+    force_mkdir(dir_name + '/contour', clean=True)
+    # For post-contour debugging information.
+    force_mkdir(dir_name + '/scratch', clean=True)
+    return dir_name
+
+
+def force_mkdir(dir_name, clean=False):
+    """Creates a directory if it doesn't already exist.
+
+    Args:
+        dir_name: Name of the directory to create.
+        clean:    (optional) If set to true, cleans image files from the
+                  directory (if it already exists).
+    """
+    if os.path.exists(dir_name):
+        if clean:
+            for image in glob.glob('%s/*.png' % dir_name):
+                os.remove(image)
+    else:
+        os.makedirs(dir_name)
+
+
+def debug_print(s, *args, **kwargs):
+    """Only prints if the test is running in debug mode."""
+    if DEBUG:
+        print(s, *args, **kwargs)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/apps/CameraITS/tests/scene1/test_dng_noise_model.py b/apps/CameraITS/tests/scene1/test_dng_noise_model.py
index 02bce79..d1c7fbe 100644
--- a/apps/CameraITS/tests/scene1/test_dng_noise_model.py
+++ b/apps/CameraITS/tests/scene1/test_dng_noise_model.py
@@ -12,30 +12,31 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import its.device
-import its.caps
-import its.objects
-import its.image
 import os.path
-from matplotlib import pylab
+import its.caps
+import its.device
+import its.image
+import its.objects
 import matplotlib
-import matplotlib.pyplot
+from matplotlib import pylab
+
+NAME = os.path.basename(__file__).split('.')[0]
+BAYER_LIST = ['R', 'GR', 'GB', 'B']
+DIFF_THRESH = 0.0005  # absolute variance delta threshold
+FRAC_THRESH = 0.2  # relative variance delta threshold
+NUM_STEPS = 4
+STATS_GRID = 49  # center 2.04% of image for calculations
+
 
 def main():
-    """Verify that the DNG raw model parameters are correct.
-    """
-    NAME = os.path.basename(__file__).split(".")[0]
-
-    NUM_STEPS = 4
+    """Verify that the DNG raw model parameters are correct."""
 
     # Pass if the difference between expected and computed variances is small,
-    # defined as being within an absolute variance delta of 0.0005, or within
-    # 20% of the expected variance, whichever is larger; this is to allow the
+    # defined as being within an absolute variance delta or relative variance
+    # delta of the expected variance, whichever is larger. This is to allow the
     # test to pass in the presence of some randomness (since this test is
     # measuring noise of a small patch) and some imperfect scene conditions
     # (since ITS doesn't require a perfectly uniformly lit scene).
-    DIFF_THRESH = 0.0005
-    FRAC_THRESH = 0.2
 
     with its.device.ItsSession() as cam:
 
@@ -45,69 +46,85 @@
                              its.caps.manual_sensor(props) and
                              its.caps.read_3a(props) and
                              its.caps.per_frame_control(props))
+        debug = its.caps.debug_mode()
 
         white_level = float(props['android.sensor.info.whiteLevel'])
         cfa_idxs = its.image.get_canonical_cfa_order(props)
+        aax = props['android.sensor.info.activeArraySize']['left']
+        aay = props['android.sensor.info.activeArraySize']['top']
+        aaw = props['android.sensor.info.activeArraySize']['right']-aax
+        aah = props['android.sensor.info.activeArraySize']['bottom']-aay
 
         # Expose for the scene with min sensitivity
         sens_min, sens_max = props['android.sensor.info.sensitivityRange']
         sens_step = (sens_max - sens_min) / NUM_STEPS
-        s_ae,e_ae,_,_,f_dist  = cam.do_3a(get_results=True)
+        s_ae, e_ae, _, _, f_dist = cam.do_3a(get_results=True)
         s_e_prod = s_ae * e_ae
         sensitivities = range(sens_min, sens_max, sens_step)
 
-        var_expected = [[],[],[],[]]
-        var_measured = [[],[],[],[]]
+        var_expected = [[], [], [], []]
+        var_measured = [[], [], [], []]
+        x = STATS_GRID/2  # center in H of STATS_GRID
+        y = STATS_GRID/2  # center in W of STATS_GRID
         for sens in sensitivities:
 
-            # Capture a raw frame with the desired sensitivity.
+            # Capture a raw frame with the desired sensitivity
             exp = int(s_e_prod / float(sens))
             req = its.objects.manual_capture_request(sens, exp, f_dist)
-            cap = cam.do_capture(req, cam.CAP_RAW)
+            if debug:
+                cap = cam.do_capture(req, cam.CAP_RAW)
+                planes = its.image.convert_capture_to_planes(cap, props)
+            else:
+                cap = cam.do_capture(req, {'format': 'rawStats',
+                                           'gridWidth': aaw/STATS_GRID,
+                                           'gridHeight': aah/STATS_GRID})
+                mean_img, var_img = its.image.unpack_rawstats_capture(cap)
 
-            # Test each raw color channel (R, GR, GB, B):
-            noise_profile = cap["metadata"]["android.sensor.noiseProfile"]
-            assert((len(noise_profile)) == 4)
-            for ch in range(4):
+            # Test each raw color channel (R, GR, GB, B)
+            noise_profile = cap['metadata']['android.sensor.noiseProfile']
+            assert len(noise_profile) == len(BAYER_LIST)
+            for i in range(len(BAYER_LIST)):
                 # Get the noise model parameters for this channel of this shot.
-                s,o = noise_profile[cfa_idxs[ch]]
+                ch = cfa_idxs[i]
+                s, o = noise_profile[ch]
 
-                # Get a center tile of the raw channel, and compute the mean.
                 # Use a very small patch to ensure gross uniformity (i.e. so
                 # non-uniform lighting or vignetting doesn't affect the variance
-                # calculation).
-                plane = its.image.convert_capture_to_planes(cap, props)[ch]
-                black_level = its.image.get_black_level(
-                    ch, props, cap["metadata"])
-                plane = (plane * white_level - black_level) / (
-                    white_level - black_level)
-                tile = its.image.get_image_patch(plane, 0.49,0.49,0.02,0.02)
-                mean = tile.mean()
+                # calculation)
+                black_level = its.image.get_black_level(i, props,
+                                                        cap['metadata'])
+                level_range = white_level - black_level
+                if debug:
+                    plane = ((planes[i] * white_level - black_level) /
+                             level_range)
+                    tile = its.image.get_image_patch(plane, 0.49, 0.49,
+                                                     0.02, 0.02)
+                    mean_img_ch = tile.mean()
+                    var_measured[i].append(
+                            its.image.compute_image_variances(tile)[0])
+                else:
+                    mean_img_ch = (mean_img[x, y, ch]-black_level)/level_range
+                    var_measured[i].append(var_img[x, y, ch]/level_range**2)
+                var_expected[i].append(s * mean_img_ch + o)
 
-                # Calculate the expected variance based on the model, and the
-                # measured variance from the tile.
-                var_measured[ch].append(
-                        its.image.compute_image_variances(tile)[0])
-                var_expected[ch].append(s * mean + o)
-
-    for ch in range(4):
-        pylab.plot(sensitivities, var_expected[ch], "rgkb"[ch],
-                label=["R","GR","GB","B"][ch]+" expected")
-        pylab.plot(sensitivities, var_measured[ch], "rgkb"[ch]+"--",
-                label=["R", "GR", "GB", "B"][ch]+" measured")
-    pylab.xlabel("Sensitivity")
-    pylab.ylabel("Center patch variance")
+    for i, ch in enumerate(BAYER_LIST):
+        pylab.plot(sensitivities, var_expected[i], 'rgkb'[i],
+                   label=ch+' expected')
+        pylab.plot(sensitivities, var_measured[i], 'rgkb'[i]+'--',
+                   label=ch+' measured')
+    pylab.xlabel('Sensitivity')
+    pylab.ylabel('Center patch variance')
     pylab.legend(loc=2)
-    matplotlib.pyplot.savefig("%s_plot.png" % (NAME))
+    matplotlib.pyplot.savefig('%s_plot.png' % NAME)
 
-    # Pass/fail check.
-    for ch in range(4):
-        diffs = [var_measured[ch][i] - var_expected[ch][i]
-                 for i in range(NUM_STEPS)]
-        print "Diffs (%s):"%(["R","GR","GB","B"][ch]), diffs
-        for i,diff in enumerate(diffs):
-            thresh = max(DIFF_THRESH, FRAC_THRESH * var_expected[ch][i])
-            assert(diff <= thresh)
+    # PASS/FAIL check
+    for i, ch in enumerate(BAYER_LIST):
+        diffs = [var_measured[i][j] - var_expected[i][j]
+                 for j in range(NUM_STEPS)]
+        print 'Diffs (%s):'%(ch), diffs
+        for j, diff in enumerate(diffs):
+            thresh = max(DIFF_THRESH, FRAC_THRESH*var_expected[i][j])
+            assert diff <= thresh
 
 if __name__ == '__main__':
     main()
diff --git a/apps/CameraITS/tests/scene1/test_format_combos.py b/apps/CameraITS/tests/scene1/test_format_combos.py
index 1519237..ca65e4f 100644
--- a/apps/CameraITS/tests/scene1/test_format_combos.py
+++ b/apps/CameraITS/tests/scene1/test_format_combos.py
@@ -20,15 +20,13 @@
 import its.target
 import sys
 import os
-import os.path
 
-# Change this to True, to have the test break at the first failure.
-stop_at_first_failure = False
+NAME = os.path.basename(__file__).split(".")[0]
+STOP_AT_FIRST_FAILURE = False  # change to True to have test break @ 1st FAIL
+
 
 def main():
-    """Test different combinations of output formats.
-    """
-    NAME = os.path.basename(__file__).split(".")[0]
+    """Test different combinations of output formats."""
 
     with its.device.ItsSession() as cam:
 
@@ -44,33 +42,33 @@
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
         req_aut = its.objects.auto_capture_request()
         req_man = its.objects.manual_capture_request(s, e)
-        reqs = [req_aut, # R0
-                req_man] # R1
+        reqs = [req_aut,  # R0
+                req_man]  # R1
 
         # 10 different combos of output formats; some are single surfaces, and
         # some are multiple surfaces.
-        wyuv,hyuv = its.objects.get_available_output_sizes("yuv", props)[-1]
-        wjpg,hjpg = its.objects.get_available_output_sizes("jpg", props)[-1]
-        fmt_yuv_prev = {"format":"yuv", "width":wyuv, "height":hyuv}
-        fmt_yuv_full = {"format":"yuv"}
-        fmt_jpg_prev = {"format":"jpeg","width":wjpg, "height":hjpg}
-        fmt_jpg_full = {"format":"jpeg"}
-        fmt_raw_full = {"format":"raw"}
-        fmt_combos =[
-                [fmt_yuv_prev],                             # F0
-                [fmt_yuv_full],                             # F1
-                [fmt_jpg_prev],                             # F2
-                [fmt_jpg_full],                             # F3
-                [fmt_raw_full],                             # F4
-                [fmt_yuv_prev, fmt_jpg_prev],               # F5
-                [fmt_yuv_prev, fmt_jpg_full],               # F6
-                [fmt_yuv_prev, fmt_raw_full],               # F7
-                [fmt_yuv_prev, fmt_jpg_prev, fmt_raw_full], # F8
-                [fmt_yuv_prev, fmt_jpg_full, fmt_raw_full]] # F9
+        wyuv, hyuv = its.objects.get_available_output_sizes("yuv", props)[-1]
+        wjpg, hjpg = its.objects.get_available_output_sizes("jpg", props)[-1]
+        fmt_yuv_prev = {"format": "yuv", "width": wyuv, "height": hyuv}
+        fmt_yuv_full = {"format": "yuv"}
+        fmt_jpg_prev = {"format": "jpeg", "width": wjpg, "height": hjpg}
+        fmt_jpg_full = {"format": "jpeg"}
+        fmt_raw_full = {"format": "raw"}
+        fmt_combos = [
+            [fmt_yuv_prev],                              # F0
+            [fmt_yuv_full],                              # F1
+            [fmt_jpg_prev],                              # F2
+            [fmt_jpg_full],                              # F3
+            [fmt_raw_full],                              # F4
+            [fmt_yuv_prev, fmt_jpg_prev],                # F5
+            [fmt_yuv_prev, fmt_jpg_full],                # F6
+            [fmt_yuv_prev, fmt_raw_full],                # F7
+            [fmt_yuv_prev, fmt_jpg_prev, fmt_raw_full],  # F8
+            [fmt_yuv_prev, fmt_jpg_full, fmt_raw_full]]  # F9
 
         # Two different burst lengths: single frame, and 3 frames.
-        burst_lens = [1, # B0
-                      3] # B1
+        burst_lens = [1,  # B0
+                      3]  # B1
 
         # There are 2x10x2=40 different combinations. Run through them all.
         n = 0
@@ -82,15 +80,14 @@
                         successes.append((n,r,f,b))
                         print "==> Success[%02d]: R%d F%d B%d" % (n,r,f,b)
 
-                        # Dump the captures out to jpegs.
-                        if not isinstance(caps, list):
-                            caps = [caps]
-                        elif isinstance(caps[0], list):
-                            caps = sum(caps, [])
-                        for c,cap in enumerate(caps):
-                            img = its.image.convert_capture_to_rgb_image(cap,
-                                    props=props)
-                            if debug:
+                        # Dump the captures out to jpegs in debug mode.
+                        if debug:
+                            if not isinstance(caps, list):
+                                caps = [caps]
+                            elif isinstance(caps[0], list):
+                                caps = sum(caps, [])
+                            for c, cap in enumerate(caps):
+                                img = its.image.convert_capture_to_rgb_image(cap, props=props)
                                 its.image.write_image(img,
                                     "%s_n%02d_r%d_f%d_b%d_c%d.jpg"%(NAME,n,r,f,b,c))
 
@@ -98,8 +95,8 @@
                         print e
                         print "==> Failure[%02d]: R%d F%d B%d" % (n,r,f,b)
                         failures.append((n,r,f,b))
-                        if stop_at_first_failure:
-                            sys.exit(0)
+                        if STOP_AT_FIRST_FAILURE:
+                            sys.exit(1)
                     n += 1
 
         num_fail = len(failures)
@@ -118,8 +115,8 @@
         print ""
 
         # The test passes if all the combinations successfully capture.
-        assert(num_fail == 0)
-        assert(num_success == num_total)
+        assert num_fail == 0
+        assert num_success == num_total
 
 if __name__ == '__main__':
     main()
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index 86c3e77..cc3ef05 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -12,32 +12,33 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import its.image
-import its.device
-import its.objects
-import its.caps
-import time
-import math
-from matplotlib import pylab
-import os.path
-import matplotlib
-import matplotlib.pyplot
-import json
-from PIL import Image
-import numpy
-import cv2
 import bisect
-import scipy.spatial
+import json
+import math
+import os.path
 import sys
+import time
+
+import cv2
+import its.caps
+import its.device
+import its.image
+import its.objects
+import matplotlib
+from matplotlib import pylab
+import matplotlib.pyplot
+import numpy
+from PIL import Image
+import scipy.spatial
 
 NAME = os.path.basename(__file__).split(".")[0]
 
-# Capture 210 VGA frames (which is 7s at 30fps)
-N = 210
-W,H = 640,480
-FEATURE_MARGIN = H * 0.20 / 2 # Only take feature points from the center 20%
-                              # so that the rotation measured have much less
-                              # of rolling shutter effect
+W, H = 640, 480
+FPS = 30
+TEST_LENGTH = 7  # seconds
+FEATURE_MARGIN = 0.20  # Only take feature points from the center 20%
+                       # so that the rotation measured have much less of rolling
+                       # shutter effect
 
 MIN_FEATURE_PTS = 30          # Minimum number of feature points required to
                               # perform rotation analysis
@@ -48,15 +49,15 @@
 
 MIN_GYRO_SMP_RATE = 100.0     # Minimum gyro sample rate
 
-FEATURE_PARAMS = dict( maxCorners = 240,
-                       qualityLevel = 0.3,
-                       minDistance = 7,
-                       blockSize = 7 )
+FEATURE_PARAMS = dict(maxCorners=240,
+                      qualityLevel=0.3,
+                      minDistance=7,
+                      blockSize=7)
 
-LK_PARAMS = dict( winSize  = (15, 15),
-                  maxLevel = 2,
-                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,
-                        10, 0.03))
+LK_PARAMS = dict(winSize=(15, 15),
+                 maxLevel=2,
+                 criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,
+                           10, 0.03))
 
 # Constants to convert between different time units (for clarity).
 SEC_TO_NSEC = 1000*1000*1000.0
@@ -76,28 +77,57 @@
 FACING_BACK = 1
 FACING_EXTERNAL = 2
 
+
 def main():
     """Test if image and motion sensor events are well synchronized.
 
     The instructions for running this test are in the SensorFusion.pdf file in
     the same directory as this test.
 
-    The command-line argument "replay" may be optionally provided. Without this
-    argument, the test will collect a new set of camera+gyro data from the
-    device and then analyze it (and it will also dump this data to files in the
-    current directory). If the "replay" argument is provided, then the script
-    will instead load the dumped data from a previous run and analyze that
-    instead. This can be helpful for developers who are digging for additional
-    information on their measurements.
+    Note that if fps*test_length is too large, write speeds may become a
+    bottleneck and camera capture will slow down or stop.
+
+    Command line arguments:
+        fps:         FPS to capture with during the test
+        img_size:    Comma-separated dimensions of captured images (defaults to
+                     640x480). Ex: "img_size=<width>,<height>"
+        replay:      Without this argument, the test will collect a new set of
+                     camera+gyro data from the device and then analyze it (and
+                     it will also dump this data to files in the current
+                     directory).  If the "replay" argument is provided, then the
+                     script will instead load the dumped data from a previous
+                     run and analyze that instead. This can be helpful for
+                     developers who are digging for additional information on
+                     their measurements.
+        test_length: How long the test should run for (in seconds)
     """
 
+    fps = FPS
+    w, h = W, H
+    test_length = TEST_LENGTH
+    for s in sys.argv[1:]:
+        if s[:4] == "fps=" and len(s) > 4:
+            fps = int(s[4:])
+        elif s[:9] == "img_size=" and len(s) > 9:
+            # 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:])
+
     # 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
     # RGB images as numpy arrays.
     if "replay" not in sys.argv:
-        events, frames = collect_data()
+        if w * h > 640 * 480 or fps * test_length > 300:
+            warning_str = (
+                "Warning: Your test parameters may require fast write speeds "
+                "to run smoothly.  If you run into problems, consider smaller "
+                "values of \'w\', \'h\', \'fps\', or \'test_length\'."
+            )
+            print warning_str
+        events, frames = collect_data(fps, w, h, test_length)
     else:
-        events, frames = load_data()
+        events, frames, _, h = load_data()
 
     # Sanity check camera timestamps are enclosed by sensor timestamps
     # This will catch bugs where camera and gyro timestamps go completely out
@@ -109,25 +139,29 @@
     min_gyro_time = min(gyro_times) * NSEC_TO_SEC
     max_gyro_time = max(gyro_times) * NSEC_TO_SEC
     if not (min_cam_time > min_gyro_time and max_cam_time < max_gyro_time):
-        print "Test failed: camera timestamps [%f,%f] " \
-              "are not enclosed by gyro timestamps [%f, %f]" % (
-            min_cam_time, max_cam_time, min_gyro_time, max_gyro_time)
-        assert(0)
+        fail_str = ("Test failed: "
+                    "camera timestamps [%f,%f] "
+                    "are not enclosed by "
+                    "gyro timestamps [%f, %f]"
+                   ) % (min_cam_time, max_cam_time,
+                        min_gyro_time, max_gyro_time)
+        print fail_str
+        assert 0
 
     cam_frame_range = max_cam_time - min_cam_time
     gyro_time_range = max_gyro_time - min_gyro_time
     gyro_smp_per_sec = len(gyro_times) / gyro_time_range
     print "Camera frame range", max_cam_time - min_cam_time
     print "Gyro samples per second", gyro_smp_per_sec
-    assert(cam_frame_range < MAX_CAM_FRM_RANGE_SEC)
-    assert(gyro_smp_per_sec > MIN_GYRO_SMP_RATE)
+    assert cam_frame_range < MAX_CAM_FRM_RANGE_SEC
+    assert gyro_smp_per_sec > MIN_GYRO_SMP_RATE
 
     # Compute the camera rotation displacements (rad) between each pair of
     # adjacent frames.
-    cam_rots = get_cam_rotations(frames, events["facing"])
+    cam_rots = get_cam_rotations(frames, events["facing"], h)
     if max(abs(cam_rots)) < THRESH_MIN_ROT:
         print "Device wasn't moved enough"
-        assert(0)
+        assert 0
 
     # Find the best offset (time-shift) to align the gyro and camera motion
     # traces; this function integrates the shifted gyro data between camera
@@ -136,15 +170,16 @@
     offset = get_best_alignment_offset(cam_times, cam_rots, events["gyro"])
 
     # Plot the camera and gyro traces after applying the best shift.
-    cam_times = cam_times + offset*SEC_TO_NSEC
+    cam_times += offset*SEC_TO_NSEC
     gyro_rots = get_gyro_rotations(events["gyro"], cam_times)
     plot_rotations(cam_rots, gyro_rots)
 
     # Pass/fail based on the offset and also the correlation distance.
     dist = scipy.spatial.distance.correlation(cam_rots, gyro_rots)
     print "Best correlation of %f at shift of %.2fms"%(dist, offset*SEC_TO_MSEC)
-    assert(dist < THRESH_MAX_CORR_DIST)
-    assert(abs(offset) < THRESH_MAX_SHIFT_MS*MSEC_TO_SEC)
+    assert dist < THRESH_MAX_CORR_DIST
+    assert abs(offset) < THRESH_MAX_SHIFT_MS*MSEC_TO_SEC
+
 
 def get_best_alignment_offset(cam_times, cam_rots, gyro_events):
     """Find the best offset to align the camera and gyro traces.
@@ -162,7 +197,7 @@
     """
     # Measure the corr. dist. over a shift of up to +/- 50ms (0.5ms step size).
     # Get the shift corresponding to the best (lowest) score.
-    candidates = numpy.arange(-50,50.5,0.5).tolist()
+    candidates = numpy.arange(-50, 50.5, 0.5).tolist()
     dists = []
     for shift in candidates:
         times = cam_times + shift*MSEC_TO_NSEC
@@ -182,20 +217,20 @@
     i = dists.index(best_corr_dist)
     candidates = candidates[i-20:i+21]
     dists = dists[i-20:i+21]
-    a,b,c = numpy.polyfit(candidates, dists, 2)
+    a, b, c = numpy.polyfit(candidates, dists, 2)
     exact_best_shift = -b/(2*a)
     if abs(best_shift - exact_best_shift) > 2.0 or a <= 0 or c <= 0:
         print "Test failed; bad fit to time-shift curve"
-        print "best_shift %f, exact_best_shift %f, a %f, c %f" % (best_shift,
-                exact_best_shift, a, c)
-        assert(0)
+        print "best_shift %f, exact_best_shift %f, a %f, c %f" % (
+            best_shift, exact_best_shift, a, c)
+        assert 0
 
     xfit = numpy.arange(candidates[0], candidates[-1], 0.05).tolist()
     yfit = [a*x*x+b*x+c for x in xfit]
-    fig = matplotlib.pyplot.figure()
-    pylab.plot(candidates, dists, 'r', label="data")
-    pylab.plot(xfit, yfit, 'b', label="fit")
-    pylab.plot([exact_best_shift+x for x in [-0.1,0,0.1]], [0,0.01,0], 'b')
+    matplotlib.pyplot.figure()
+    pylab.plot(candidates, dists, "r", label="data")
+    pylab.plot(xfit, yfit, "", label="fit")
+    pylab.plot([exact_best_shift+x for x in [-0.1, 0, 0.1]], [0, 0.01, 0], "b")
     pylab.xlabel("Relative horizontal shift between curves (ms)")
     pylab.ylabel("Correlation distance")
     pylab.legend()
@@ -203,6 +238,7 @@
 
     return exact_best_shift * MSEC_TO_SEC
 
+
 def plot_rotations(cam_rots, gyro_rots):
     """Save a plot of the camera vs. gyro rotational measurements.
 
@@ -212,17 +248,18 @@
     """
     # For the plot, scale the rotations to be in degrees.
     scale = 360/(2*math.pi)
-    fig = matplotlib.pyplot.figure()
-    cam_rots = cam_rots * scale
-    gyro_rots = gyro_rots * scale
-    pylab.plot(range(len(cam_rots)), cam_rots, 'r', label="camera")
-    pylab.plot(range(len(gyro_rots)), gyro_rots, 'b', label="gyro")
+    matplotlib.pyplot.figure()
+    cam_rots *= scale
+    gyro_rots *= scale
+    pylab.plot(range(len(cam_rots)), cam_rots, "r", label="camera")
+    pylab.plot(range(len(gyro_rots)), gyro_rots, "b", label="gyro")
     pylab.legend()
     pylab.xlabel("Camera frame number")
     pylab.ylabel("Angular displacement between adjacent camera frames (deg)")
     pylab.xlim([0, len(cam_rots)])
     matplotlib.pyplot.savefig("%s_plot.png" % (NAME))
 
+
 def get_gyro_rotations(gyro_events, cam_times):
     """Get the rotation values of the gyro.
 
@@ -255,7 +292,7 @@
             deltatgyro = (tgyro1 - tgyro0) * NSEC_TO_SEC
             sgyro += vgyro * deltatgyro
         # Handle the fractional intervals at the sides of the window.
-        for side,igyro in enumerate([igyrowindow0-1, igyrowindow1]):
+        for side, igyro in enumerate([igyrowindow0-1, igyrowindow1]):
             vgyro = all_rots[igyro+1]
             tgyro0 = all_times[igyro]
             tgyro1 = all_times[igyro+1]
@@ -270,7 +307,8 @@
     gyro_rots = numpy.array(gyro_rots)
     return gyro_rots
 
-def get_cam_rotations(frames, facing):
+
+def get_cam_rotations(frames, facing, h):
     """Get the rotations of the camera between each pair of frames.
 
     Takes N frames and returns N-1 angular displacements corresponding to the
@@ -278,6 +316,8 @@
 
     Args:
         frames: List of N images (as RGB numpy arrays).
+        facing: Direction camera is facing
+        h:      Pixel height of each frame
 
     Returns:
         Array of N-1 camera rotation measurements (rad).
@@ -287,40 +327,42 @@
         frame = (frame * 255.0).astype(numpy.uint8)
         gframes.append(cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY))
     rots = []
-    ymin = H/2 - FEATURE_MARGIN
-    ymax = H/2 + FEATURE_MARGIN
-    for i in range(1,len(gframes)):
+
+    ymin = h*(1-FEATURE_MARGIN)/2
+    ymax = h*(1+FEATURE_MARGIN)/2
+    for i in range(1, len(gframes)):
         gframe0 = gframes[i-1]
         gframe1 = gframes[i]
         p0 = cv2.goodFeaturesToTrack(gframe0, mask=None, **FEATURE_PARAMS)
         # p0's shape is N * 1 * 2
-        mask = (p0[:,0,1] >= ymin) & (p0[:,0,1] <= ymax)
+        mask = (p0[:, 0, 1] >= ymin) & (p0[:, 0, 1] <= ymax)
         p0_filtered = p0[mask]
         if len(p0_filtered) < MIN_FEATURE_PTS:
             print "Not enough feature points in frame", i
             print "Need at least %d features, got %d" % (
-                    MIN_FEATURE_PTS, len(p0_filtered))
-            assert(0)
-        p1,st,_ = cv2.calcOpticalFlowPyrLK(gframe0, gframe1, p0_filtered, None,
-                **LK_PARAMS)
-        tform = procrustes_rotation(p0_filtered[st==1], p1[st==1])
+                MIN_FEATURE_PTS, len(p0_filtered))
+            assert 0
+        p1, st, _ = cv2.calcOpticalFlowPyrLK(gframe0, gframe1, p0_filtered,
+                                             None, **LK_PARAMS)
+        tform = procrustes_rotation(p0_filtered[st == 1], p1[st == 1])
         if facing == FACING_BACK:
             rot = -math.atan2(tform[0, 1], tform[0, 0])
         elif facing == FACING_FRONT:
             rot = math.atan2(tform[0, 1], tform[0, 0])
         else:
             print "Unknown lens facing", facing
-            assert(0)
+            assert 0
         rots.append(rot)
         if i == 1:
             # Save a debug visualization of the features that are being
             # tracked in the first frame.
             frame = frames[i]
-            for x,y in p0_filtered[st==1]:
-                cv2.circle(frame, (x,y), 3, (100,100,255), -1)
-            its.image.write_image(frame, "%s_features.png"%(NAME))
+            for x, y in p0_filtered[st == 1]:
+                cv2.circle(frame, (x, y), 3, (100, 100, 255), -1)
+            its.image.write_image(frame, "%s_features.png" % NAME)
     return numpy.array(rots)
 
+
 def get_cam_times(cam_events):
     """Get the camera frame times.
 
@@ -334,35 +376,45 @@
     """
     # Assign a time to each frame that assumes that the image is instantly
     # captured in the middle of its exposure.
-    starts = numpy.array([start for start,exptime,readout in cam_events])
-    exptimes = numpy.array([exptime for start,exptime,readout in cam_events])
-    readouts = numpy.array([readout for start,exptime,readout in cam_events])
+    starts = numpy.array([start for start, exptime, readout in cam_events])
+    exptimes = numpy.array([exptime for start, exptime, readout in cam_events])
+    readouts = numpy.array([readout for start, exptime, readout in cam_events])
     frame_times = starts + (exptimes + readouts) / 2.0
     return frame_times
 
+
 def load_data():
     """Load a set of previously captured data.
 
     Returns:
         events: Dictionary containing all gyro events and cam timestamps.
         frames: List of RGB images as numpy arrays.
+        w:      Pixel width of frames
+        h:      Pixel height of frames
     """
-    with open("%s_events.txt"%(NAME), "r") as f:
+    with open("%s_events.txt" % NAME, "r") as f:
         events = json.loads(f.read())
     n = len(events["cam"])
     frames = []
     for i in range(n):
-        img = Image.open("%s_frame%03d.png"%(NAME,i))
-        w,h = img.size[0:2]
-        frames.append(numpy.array(img).reshape(h,w,3) / 255.0)
-    return events, frames
+        img = Image.open("%s_frame%03d.png" % (NAME, i))
+        w, h = img.size[0:2]
+        frames.append(numpy.array(img).reshape(h, w, 3) / 255.0)
+    return events, frames, w, h
 
-def collect_data():
+
+def collect_data(fps, w, h, test_length):
     """Capture a new set of data from the device.
 
     Captures both motion data and camera frames, while the user is moving
     the device in a proscribed manner.
 
+    Args:
+        fps:         FPS to capture with
+        w:           Pixel width of frames
+        h:           Pixel height of frames
+        test_length: How long the test should run for (in seconds)
+
     Returns:
         events: Dictionary containing all gyro events and cam timestamps.
         frames: List of RGB images as numpy arrays.
@@ -371,7 +423,7 @@
         props = cam.get_camera_properties()
         its.caps.skip_unless(its.caps.sensor_fusion(props) and
                              its.caps.manual_sensor(props) and
-                             props['android.lens.facing'] != FACING_EXTERNAL)
+                             props["android.lens.facing"] != FACING_EXTERNAL)
 
         print "Starting sensor event collection"
         cam.start_sensor_events()
@@ -380,20 +432,19 @@
         time.sleep(0.5)
 
         # Capture the frames. OIS is disabled for manual captures.
-        facing = props['android.lens.facing']
+        facing = props["android.lens.facing"]
         if facing != FACING_FRONT and facing != FACING_BACK:
             print "Unknown lens facing", facing
-            assert(0)
+            assert 0
 
-        fmt = {"format":"yuv", "width":W, "height":H}
-        s,e,_,_,_ = cam.do_3a(get_results=True, do_af=False)
+        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.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]*N, fmt)
+            w, h, s, e*NSEC_TO_MSEC)
+        caps = cam.do_capture([req]*fps*test_length, fmt)
 
         # Get the gyro events.
         print "Reading out sensor events"
@@ -406,38 +457,42 @@
         exptimes = [c["metadata"]["android.sensor.exposureTime"] for c in caps]
         readouts = [c["metadata"]["android.sensor.rollingShutterSkew"]
                     for c in caps]
-        events = {"gyro": gyro, "cam": zip(starts,exptimes,readouts),
+        events = {"gyro": gyro, "cam": zip(starts, exptimes, readouts),
                   "facing": facing}
-        with open("%s_events.txt"%(NAME), "w") as f:
+        with open("%s_events.txt" % NAME, "w") as f:
             f.write(json.dumps(events))
 
         # Convert the frames to RGB.
         print "Dumping frames"
         frames = []
-        for i,c in enumerate(caps):
+        for i, c in enumerate(caps):
             img = its.image.convert_capture_to_rgb_image(c)
             frames.append(img)
-            its.image.write_image(img, "%s_frame%03d.png"%(NAME,i))
+            its.image.write_image(img, "%s_frame%03d.png" % (NAME, i))
 
         return events, frames
 
+
 def procrustes_rotation(X, Y):
-    """
+    """Performs a Procrustes analysis to conform points in X to Y.
+
     Procrustes analysis determines a linear transformation (translation,
     reflection, orthogonal rotation and scaling) of the points in Y to best
     conform them to the points in matrix X, using the sum of squared errors
     as the goodness of fit criterion.
 
     Args:
-        X, Y: Matrices of target and input coordinates.
+        X: Target coordinate matrix
+        Y: Input coordinate matrix
 
     Returns:
         The rotation component of the transformation that maps X to Y.
     """
     X0 = (X-X.mean(0)) / numpy.sqrt(((X-X.mean(0))**2.0).sum())
     Y0 = (Y-Y.mean(0)) / numpy.sqrt(((Y-Y.mean(0))**2.0).sum())
-    U,s,Vt = numpy.linalg.svd(numpy.dot(X0.T, Y0),full_matrices=False)
+    U, _, Vt = numpy.linalg.svd(numpy.dot(X0.T, Y0), full_matrices=False)
     return numpy.dot(Vt.T, U.T)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     main()
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 20a9c3d..a6fc759 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -26,9 +26,21 @@
 
 CHART_DELAY = 1  # seconds
 FACING_EXTERNAL = 2
+NUM_TRYS = 2
 SKIP_RET_CODE = 101  # note this must be same as tests/scene*/test_*
 
 
+def evaluate_socket_failure(err_file_path):
+    """Determine if test fails due to socket FAIL."""
+    socket_fail = False
+    with open(err_file_path, 'r') as ferr:
+        for line in ferr:
+            if (line.find('socket.error') != -1 or
+                line.find('Problem with socket') != -1):
+                socket_fail = True
+    return socket_fail
+
+
 def skip_sensor_fusion():
     """Determine if sensor fusion test is skipped for this camera."""
 
@@ -47,17 +59,24 @@
 
     Script should be run from the top-level CameraITS directory.
 
-    Command line Arguments:
-        camera: the camera(s) to be tested. Use comma to separate multiple
-                camera Ids. Ex: "camera=0,1" or "camera=1"
-        scenes: the test scene(s) to be executed. Use comma to separate multiple
-                scenes. Ex: "scenes=scene0,scene1" or "scenes=0,1,sensor_fusion"
-                (sceneX can be abbreviated by X where X is a integer)
-        chart: [Experimental] another android device served as test chart
-               display. When this argument presents, change of test scene will
-               be handled automatically. Note that this argument requires
-               special physical/hardware setup to work and may not work on
-               all android devices.
+    Command line arguments:
+        camera:  the camera(s) to be tested. Use comma to separate multiple
+                 camera Ids. Ex: "camera=0,1" or "camera=1"
+        device:  device id for adb
+        scenes:  the test scene(s) to be executed. Use comma to separate
+                 multiple scenes. Ex: "scenes=scene0,scene1" or
+                 "scenes=0,1,sensor_fusion" (sceneX can be abbreviated by X
+                 where X is a integer)
+        chart:   [Experimental] another android device served as test chart
+                 display. When this argument presents, change of test scene
+                 will be handled automatically. Note that this argument
+                 requires special physical/hardware setup to work and may not
+                 work on all android devices.
+        result:  Device ID to forward results to (in addition to the device
+                 that the tests are running on).
+        rot_rig: [Experimental] ID of the rotation rig being used (formatted as
+                 "<vendor ID>:<product ID>:<channel #>" or "default")
+        tmp_dir: location of temp directory for output files
     """
 
     # Not yet mandated tests
@@ -116,7 +135,7 @@
     chart_host_id = None
     result_device_id = None
     rot_rig_id = None
-
+    tmp_dir = None
     for s in sys.argv[1:]:
         if s[:7] == "camera=" and len(s) > 7:
             camera_ids = s[7:].split(',')
@@ -129,6 +148,8 @@
         elif s[:8] == 'rot_rig=' and len(s) > 8:
             rot_rig_id = s[8:]  # valid values: 'default' or '$VID:$PID:$CH'
             # The default '$VID:$PID:$CH' is '04d8:fc73:1'
+        elif s[:8] == 'tmp_dir=' and len(s) > 8:
+            tmp_dir = s[8:]
 
     auto_scene_switch = chart_host_id is not None
     merge_result_switch = result_device_id is not None
@@ -168,7 +189,7 @@
         results[s] = {result_key: ItsSession.RESULT_NOT_EXECUTED}
 
     # Make output directories to hold the generated files.
-    topdir = tempfile.mkdtemp()
+    topdir = tempfile.mkdtemp(dir=tmp_dir)
     subprocess.call(['chmod', 'g+rx', topdir])
     print "Saving output files to:", topdir, "\n"
 
@@ -279,7 +300,7 @@
                     if merge_result_switch and camera_ids[0] == '0':
                         # Send an input event to keep the screen not dimmed.
                         # Since we are not using camera of chart screen, FOCUS event
-                        # should does nothing but keep the screen from dimming.
+                        # should do nothing but keep the screen from dimming.
                         # The "sleep after x minutes of inactivity" display setting
                         # determines how long this command can keep screen bright.
                         # Setting it to something like 30 minutes should be enough.
@@ -287,26 +308,38 @@
                                % chart_host_id)
                         subprocess.call(cmd.split())
                 t0 = time.time()
-                outdir = os.path.join(topdir, camera_id, scene)
-                outpath = os.path.join(outdir, testname+'_stdout.txt')
-                errpath = os.path.join(outdir, testname+'_stderr.txt')
-                if scene == 'sensor_fusion':
-                    if skip_code is not SKIP_RET_CODE:
-                        if rot_rig_id:
-                            print 'Rotating phone w/ rig %s' % rot_rig_id
-                            rig = ('python tools/rotation_rig.py rotator=%s' %
-                                   rot_rig_id)
-                            subprocess.Popen(rig.split())
+                for num_try in range(NUM_TRYS):
+                    outdir = os.path.join(topdir, camera_id, scene)
+                    outpath = os.path.join(outdir, testname+'_stdout.txt')
+                    errpath = os.path.join(outdir, testname+'_stderr.txt')
+                    if scene == 'sensor_fusion':
+                        if skip_code is not SKIP_RET_CODE:
+                            if rot_rig_id:
+                                print 'Rotating phone w/ rig %s' % rot_rig_id
+                                rig = ('python tools/rotation_rig.py rotator=%s' %
+                                       rot_rig_id)
+                                subprocess.Popen(rig.split())
+                            else:
+                                print 'Rotate phone 15s as shown in SensorFusion.pdf'
                         else:
-                            print 'Rotate phone 15s as shown in SensorFusion.pdf'
+                            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]
+                        with open(outpath, 'w') as fout, open(errpath, 'w') as ferr:
+                            test_code = subprocess.call(
+                                cmd, stderr=ferr, stdout=fout, cwd=outdir)
+                    if test_code == 0 or test_code == SKIP_RET_CODE:
+                        break
                     else:
-                        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]
-                    with open(outpath, 'w') as fout, open(errpath, 'w') as ferr:
-                        test_code = subprocess.call(
-                            cmd, stderr=ferr, stdout=fout, cwd=outdir)
+                        socket_fail = evaluate_socket_failure(errpath)
+                        if socket_fail:
+                            if num_try != NUM_TRYS-1:
+                                print ' Retry %s/%s' % (scene, testname)
+                            else:
+                                break
+                        else:
+                            break
                 t1 = time.time()
 
                 test_failed = False
diff --git a/apps/CameraITS/tools/run_sensor_fusion_box.py b/apps/CameraITS/tools/run_sensor_fusion_box.py
index 6eb8ceb..ec16b3d 100644
--- a/apps/CameraITS/tools/run_sensor_fusion_box.py
+++ b/apps/CameraITS/tools/run_sensor_fusion_box.py
@@ -14,49 +14,80 @@
 
 import os
 import os.path
+import re
 import subprocess
 import sys
 import tempfile
 import time
 
 import its.device
-# from its.device import ItsSession
+import numpy
 
-NUM_RUNS = 2
 SCENE_NAME = 'sensor_fusion'
 SKIP_RET_CODE = 101
 TEST_NAME = 'test_sensor_fusion'
 TEST_DIR = os.path.join(os.getcwd(), 'tests', SCENE_NAME)
+W, H = 640, 480
+
+# For finding best correlation shifts from test output logs.
+SHIFT_RE = re.compile('^Best correlation of [0-9.]+ at shift of [-0-9.]+ms$')
+# For finding lines that indicate socket issues in failed test runs.
+SOCKET_FAIL_RE = re.compile(
+        r'.*((socket\.(error|timeout))|(Problem with socket)).*')
+
+FPS = 30
+TEST_LENGTH = 7  # seconds
 
 
 def main():
-    """Run all the test_sensor_fusion NUM_RUNS times.
+    """Run test_sensor_fusion NUM_RUNS times.
 
-    Save intermediate files, and producing a summary/report of the results.
+    Save intermediate files and produce a summary/report of the results.
 
     Script should be run from the top-level CameraITS directory.
 
-    Command line Arguments:
-        camera:  the camera(s) to be tested. Use comma to separate multiple
-                 camera Ids. Ex: 'camera=0,1' or 'camera=1'
-        device:  the device id for adb
-        rotator: string for rotator id in for vid:pid:ch
+    Command line arguments:
+        camera:      Camera(s) to be tested. Use comma to separate multiple
+                     camera Ids. Ex: 'camera=0,1' or 'camera=1'
+        device:      Device id for adb
+        fps:         FPS to capture with during the test
+        img_size:    Comma-separated dimensions of captured images (defaults to
+                     640x480). Ex: 'img_size=<width>,<height>'
+        num_runs:    Number of times to repeat the test
+        rotator:     String for rotator id in for vid:pid:ch
+        test_length: How long the test should run for (in seconds)
+        tmp_dir:     Location of temp directory for output files
     """
 
     camera_id = '0'
+    fps = str(FPS)
+    img_size = '%s,%s' % (W, H)
+    num_runs = 1
     rotator_ids = 'default'
+    test_length = str(TEST_LENGTH)
+    tmp_dir = None
     for s in sys.argv[1:]:
         if s[:7] == 'camera=' and len(s) > 7:
             camera_id = s[7:]
+        if s[:4] == 'fps=' and len(s) > 4:
+            fps = s[4:]
+        elif s[:9] == 'img_size=' and len(s) > 9:
+            img_size = s[9:]
+        elif s[:9] == 'num_runs=' and len(s) > 9:
+            num_runs = int(s[9:])
         elif s[:8] == 'rotator=' and len(s) > 8:
             rotator_ids = s[8:]
+        elif s[:12] == 'test_length=' and len(s) > 12:
+            test_length = s[12:]
+        elif s[:8] == 'tmp_dir=' and len(s) > 8:
+            tmp_dir = s[8:]
 
     if camera_id not in ['0', '1']:
         print 'Need to specify camera 0 or 1'
         sys.exit()
 
     # Make output directories to hold the generated files.
-    tmpdir = tempfile.mkdtemp()
+    tmpdir = tempfile.mkdtemp(dir=tmp_dir)
     print 'Saving output files to:', tmpdir, '\n'
 
     device_id = its.device.get_device_id()
@@ -68,42 +99,124 @@
         rotator_id_arg = 'rotator=' + rotator_ids
     print 'Preparing to run sensor_fusion on camera', camera_id
 
+    img_size_arg = 'img_size=' + img_size
+    print 'Image dimensions are ' + 'x'.join(img_size.split(','))
+
+    fps_arg = 'fps=' + fps
+    test_length_arg = 'test_length=' + test_length
+
     os.mkdir(os.path.join(tmpdir, camera_id))
 
-    # Run test multiple times, capturing stdout and stderr.
-    numpass = 0
-    numfail = 0
-    numskip = 0
-    for i in range(NUM_RUNS):
+    # Run test "num_runs" times, capturing stdout and stderr.
+    num_pass = 0
+    num_fail = 0
+    num_skip = 0
+    num_socket_fails = 0
+    num_non_socket_fails = 0
+    shift_list = []
+    for i in range(num_runs):
         os.mkdir(os.path.join(tmpdir, camera_id, SCENE_NAME+'_'+str(i)))
-        cmd = ('python tools/rotation_rig.py rotator=%s' % rotator_ids)
+        cmd = 'python tools/rotation_rig.py rotator=%s' % rotator_ids
         subprocess.Popen(cmd.split())
         cmd = ['python', os.path.join(TEST_DIR, TEST_NAME+'.py'),
-               device_id_arg, camera_id_arg, rotator_id_arg]
+               device_id_arg, camera_id_arg, rotator_id_arg, img_size_arg,
+               fps_arg, test_length_arg]
         outdir = os.path.join(tmpdir, camera_id, SCENE_NAME+'_'+str(i))
         outpath = os.path.join(outdir, TEST_NAME+'_stdout.txt')
         errpath = os.path.join(outdir, TEST_NAME+'_stderr.txt')
         t0 = time.time()
         with open(outpath, 'w') as fout, open(errpath, 'w') as ferr:
             retcode = subprocess.call(
-                cmd, stderr=ferr, stdout=fout, cwd=outdir)
+                    cmd, stderr=ferr, stdout=fout, cwd=outdir)
         t1 = time.time()
 
         if retcode == 0:
             retstr = 'PASS '
-            numpass += 1
+            time_shift = find_time_shift(outpath)
+            shift_list.append(time_shift)
+            num_pass += 1
         elif retcode == SKIP_RET_CODE:
             retstr = 'SKIP '
-            numskip += 1
+            num_skip += 1
         else:
             retstr = 'FAIL '
-            numfail += 1
+            time_shift = find_time_shift(outpath)
+            if time_shift is None:
+                if is_socket_fail(errpath):
+                    num_socket_fails += 1
+                else:
+                    num_non_socket_fails += 1
+            else:
+                shift_list.append(time_shift)
+            num_fail += 1
         msg = '%s %s/%s [%.1fs]' % (retstr, SCENE_NAME, TEST_NAME, t1-t0)
         print msg
 
-    test_result = '%d / %d tests passed (%.1f%%)' % (
-        numpass+numskip, NUM_RUNS, 100.0*float(numpass+numskip)/NUM_RUNS)
-    print test_result
+    if num_pass == 1:
+        print 'Best shift is %sms' % shift_list[0]
+    elif num_pass > 1:
+        shift_arr = numpy.array(shift_list)
+        mean, std = numpy.mean(shift_arr), numpy.std(shift_arr)
+        print 'Best shift mean is %sms with std. dev. of %sms' % (mean, std)
+
+    pass_percentage = 100*float(num_pass+num_skip)/num_runs
+    print '%d / %d tests passed (%.1f%%)' % (num_pass+num_skip,
+                                             num_runs,
+                                             pass_percentage)
+
+    if num_socket_fails != 0:
+        print '%s failure(s) due to socket issues' % num_socket_fails
+    if num_non_socket_fails != 0:
+        print '%s non-socket failure(s)' % num_non_socket_fails
+
+
+def is_socket_fail(err_file_path):
+    """Search through a test run's stderr log for any mention of socket issues.
+
+    Args:
+        err_file_path: File path for stderr logs to search through
+
+    Returns:
+        True if the test run failed and it was due to socket issues. Otherwise,
+        False.
+    """
+    return find_matching_line(err_file_path, SOCKET_FAIL_RE) is not None
+
+
+def find_time_shift(out_file_path):
+    """Search through a test run's stdout log for the best time shift.
+
+    Args:
+        out_file_path: File path for stdout logs to search through
+
+    Returns:
+        The best time shift, if one is found. Otherwise, returns None.
+    """
+    line = find_matching_line(out_file_path, SHIFT_RE)
+    if line is None:
+        return None
+    else:
+        words = line.split(' ')
+        # Get last word and strip off 'ms\n' before converting to a float.
+        return float(words[-1][:-3])
+
+
+def find_matching_line(file_path, regex):
+    """Search each line in the file at 'file_path' for a line matching 'regex'.
+
+    Args:
+        file_path: File path for file being searched
+        regex:     Regex used to match against lines
+
+    Returns:
+        The first matching line. If none exists, returns None.
+    """
+    with open(file_path) as f:
+        for line in f:
+            if regex.match(line):
+                return line
+    return None
+
 
 if __name__ == '__main__':
     main()
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index d82c24c..a9489d8 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -40,6 +40,8 @@
                                compatibility-device-util \
                                platform-test-annotations
 
+LOCAL_JAVA_LIBRARIES := legacy-android-test
+
 LOCAL_PACKAGE_NAME := CtsVerifier
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni \
@@ -87,18 +89,31 @@
 
 include $(BUILD_MULTI_PREBUILT)
 
+pre-installed-apps := \
+    CtsPermissionApp \
+    NotificationBot
 
-notification-bot := $(call intermediates-dir-for,APPS,NotificationBot)/package.apk
-permission-app := $(call intermediates-dir-for,APPS,CtsPermissionApp)/package.apk
-usb-companion := $(call intermediates-dir-for,APPS,CtsVerifierUSBCompanion)/package.apk
-empty-device-admin := $(call intermediates-dir-for,APPS,CtsEmptyDeviceAdmin)/package.apk
+other-required-apps := \
+    CtsEmptyDeviceAdmin \
+    CtsVerifierUSBCompanion \
+    CtsVpnFirewallAppApi23 \
+    CtsVpnFirewallAppApi24 \
+    CtsVpnFirewallAppNotAlwaysOn
+
+apps-to-include := \
+    $(pre-installed-apps) \
+    $(other-required-apps)
+
+define apk-location-for
+    $(call intermediates-dir-for,APPS,$(1))/package.apk
+endef
 
 # Builds and launches CTS Verifier on a device.
 .PHONY: cts-verifier
-cts-verifier: CtsVerifier adb NotificationBot CtsPermissionApp
+cts-verifier: CtsVerifier adb $(pre-installed-apps)
 	adb install -r $(PRODUCT_OUT)/data/app/CtsVerifier/CtsVerifier.apk \
-		&& adb install -r $(notification-bot) \
-		&& adb install -r $(permission-app) \
+		$(foreach app,$(pre-installed-apps), \
+		    && adb install -r $(call apk-location-for,$(app))) \
 		&& adb shell "am start -n com.android.cts.verifier/.CtsVerifierActivity"
 
 #
@@ -131,17 +146,12 @@
 
 cts : $(verifier-zip)
 $(verifier-zip) : $(HOST_OUT)/CameraITS
-$(verifier-zip) : $(notification-bot)
-$(verifier-zip) : $(permission-app)
-$(verifier-zip) : $(usb-companion)
-$(verifier-zip) : $(empty-device-admin)
+$(verifier-zip) : $(foreach app,$(apps-to-include),$(call apk-location-for,$(app)))
 $(verifier-zip) : $(call intermediates-dir-for,APPS,CtsVerifier)/package.apk | $(ACP)
 		$(hide) mkdir -p $(verifier-dir)
 		$(hide) $(ACP) -fp $< $(verifier-dir)/CtsVerifier.apk
-		$(ACP) -fp $(notification-bot) $(verifier-dir)/NotificationBot.apk
-		$(ACP) -fp $(permission-app) $(verifier-dir)/CtsPermissionApp.apk
-		$(ACP) -fp $(usb-companion) $(verifier-dir)/CtsVerifierUSBCompanion.apk
-		$(ACP) -fp $(empty-device-admin) $(verifier-dir)/CtsEmptyDeviceAdmin.apk
+		$(foreach app,$(apps-to-include), \
+		    $(ACP) -fp $(call apk-location-for,$(app)) $(verifier-dir)/$(app).apk;)
 		$(hide) $(ACP) -fpr $(HOST_OUT)/CameraITS $(verifier-dir)
 		$(hide) cd $(cts-dir) && zip -rq $(verifier-dir-name) $(verifier-dir-name)
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index da39dbc..a417016 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2289,6 +2289,14 @@
             </intent-filter>
         </service>
 
+        <activity android:name=".managedprovisioning.AlwaysOnVpnSettingsTestActivity"
+                android:label="@string/provisioning_byod_always_on_vpn">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.ALWAYS_ON_VPN_SETTINGS_TEST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".managedprovisioning.PermissionLockdownTestActivity"
                 android:label="@string/device_profile_owner_permission_lockdown_test">
             <intent-filter>
diff --git a/apps/CtsVerifier/assets/report/compatibility_result.css b/apps/CtsVerifier/assets/report/compatibility_result.css
index 699f45a..22eb4a9 100644
--- a/apps/CtsVerifier/assets/report/compatibility_result.css
+++ b/apps/CtsVerifier/assets/report/compatibility_result.css
@@ -14,151 +14,140 @@
 */
 
 body {
-    font-family:arial,sans-serif;
-    color:#000;
-    font-size:13px;
-    color:#333;
-    padding:10;
-    margin:10;
+  color: #333;
+  font-family: arial,sans-serif;
+  font-size: 13px;
+  margin: 10;
+  padding: 10;
 }
 
 /* Report logo and device name */
 table.title {
-    padding:5px;
-    border-width: 0px;
-    margin-left:auto;
-    margin-right:auto;
-    vertical-align:middle;
+  border-width: 0;
+  margin-left: auto;
+  margin-right: auto;
+  padding: 5px;
+  vertical-align: middle;
 }
 
 table.summary {
-    background-color: rgb(212, 233, 169);
-    border-collapse:collapse;
-    border: 0px solid #A5C639;
-    margin-left:auto;
-    margin-right:auto;
+  background-color: #d4e9a9;
+  border: 0 solid #a5c639;
+  border-collapse: collapse;
+  margin-left: auto;
+  margin-right: auto;
 }
 
 table.summary th {
-    background-color: #A5C639;
-    font-size: 1.2em;
-    padding: 0.5em;
+  background-color: #a5c639;
+  font-size: 1.2em;
+  padding: .5em;
 }
 
 table.summary td {
-    border-width: 0px 0px 0px 0px;
-    border-color: gray;
-    border-style: inset;
-    font-size: 1em;
-    padding: 0.5em;
-    vertical-align: top;
+  border: 0 inset #808080;
+  font-size: 1em;
+  padding: .5em;
+  vertical-align: top;
 }
 
 table.testsummary {
-    background-color: rgb(212, 233, 169);
-    border-collapse:collapse;
-    margin-left:auto;
-    margin-right:auto;
+  background-color: #d4e9a9;
+  border-collapse: collapse;
+  margin-left: auto;
+  margin-right: auto;
 }
 
 table.testsummary th {
-    background-color: #A5C639;
-    border: 1px outset gray;
-    padding: 0.5em;
+  background-color: #a5c639;
+  border: 1px outset #808080;
+  padding: .5em;
 }
 
 table.testsummary td {
-    border: 1px outset #A5C639;
-    padding: 0.5em;
-    text-align: center;
+  border: 1px outset #a5c639;
+  padding: .5em;
+  text-align: center;
 }
 
 table.testdetails {
-    background-color: rgb(212, 233, 169);
-    border-collapse:collapse;
-    border-width:1;
-    border-color: #A5C639;
-    margin-left:auto;
-    margin-right:auto;
-    margin-bottom: 2em;
-    vertical-align: top;
-    width: 95%;
+  background-color: #d4e9a9;
+  border-collapse: collapse;
+  border-color: #a5c639;
+  border-width: 1;
+  margin-bottom: 2em;
+  margin-left: auto;
+  margin-right: auto;
+  vertical-align: top;
+  width: 95%;
 }
 
 table.testdetails th {
-    background-color: #A5C639;
-    border-width: 1px;
-    border-color: gray;
-    border-style: outset;
-    height: 2em;
-    padding: 0.2em;
+  background-color: #a5c639;
+  border: 1px outset #808080;
+  height: 2em;
+  padding: .2em;
 }
 
 table.testdetails td {
-    border-width: 1px;
-    border-color: #A5C639;
-    border-style: outset;
-    text-align: left;
-    vertical-align: top;
-    padding: 0.2em;
+  border: 1px outset #a5c639;
+  padding: .2em;
+  text-align: left;
+  vertical-align: top;
 }
 
 table.testdetails td.module {
-    background-color: white;
-    border: 0px;
-    font-weight: bold;
+  background-color: #fff;
+  border: 0;
+  font-weight: bold;
 }
 
 /* Test cell details */
 td.failed {
-    background-color: #FA5858;
-    font-weight:bold;
-    vertical-align: top;
-    text-align: center;
+  background-color: #fa5858;
+  font-weight: bold;
+  text-align: center;
+  vertical-align: top;
 }
 
 td.failuredetails {
-    text-align: left;
+  text-align: left;
 }
 
 td.pass {
-    text-align: center;
-    margin-left:auto;
-    margin-right:auto;
+  margin-left: auto;
+  margin-right: auto;
+  text-align: center;
 }
 
 td.not_executed {
-    background-color: #A5C639;
-    vertical-align: top;
-    text-align: center;
+  background-color: #a5c639;
+  text-align: center;
+  vertical-align: top;
 }
 
 td.testname {
-    border-width: 1px;
-    border-color: #A5C639;
-    border-style: outset;
-    text-align: left;
-    vertical-align: top;
-    padding:1;
-    overflow:hidden;
+  border: 1px outset #a5c639;
+  overflow: hidden;
+  padding: 1;
+  text-align: left;
+  vertical-align: top;
 }
 
 td.testcase {
-    border-width: 1px;
-    border-color: #A5C639;
-    border-style: outset;
-    text-align: left;
-    vertical-align: top;
-    padding:1;
-    overflow:hidden;
-    font-weight:bold;
+  border: 1px outset #a5c639;
+  font-weight: bold;
+  overflow: hidden;
+  padding: 1;
+  text-align: left;
+  vertical-align: top;
 }
 
 div.details {
-    white-space: pre-wrap;       /* css-3 */
-    white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
-    white-space: -pre-wrap;      /* Opera 4-6 */
-    white-space: -o-pre-wrap;    /* Opera 7 */
-    word-wrap: break-word;       /* Internet Explorer 5.5+ */
-    overflow:auto;
+  overflow: auto;
+  white-space: pre-wrap;       /* css-3 */
+  white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
+  white-space: -pre-wrap;      /* Opera 4-6 */
+  white-space: -o-pre-wrap;    /* Opera 7 */
+  word-wrap: break-word;       /* Internet Explorer 5.5+ */
 }
diff --git a/apps/CtsVerifier/jni/verifier/Android.mk b/apps/CtsVerifier/jni/verifier/Android.mk
index 1e43211..42e2d26 100644
--- a/apps/CtsVerifier/jni/verifier/Android.mk
+++ b/apps/CtsVerifier/jni/verifier/Android.mk
@@ -32,5 +32,7 @@
 LOCAL_SHARED_LIBRARIES := liblog \
 		libnativehelper_compat_libc++
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index cb307f1..e4249c4 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -24,6 +24,7 @@
 -keep class org.mockito.** { *; }
 -keep interface org.mockito.** { *; }
 -keep class com.google.dexmaker.** { *; }
+-keep class com.android.dx.mockito.** { *; }
 -keep interface com.google.dexmaker.** { *; }
 
 -dontwarn android.hardware.Sensor
diff --git a/apps/CtsVerifier/res/layout-watch/da_policy_main.xml b/apps/CtsVerifier/res/layout-watch/da_policy_main.xml
new file mode 100644
index 0000000..abc2f74
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-watch/da_policy_main.xml
@@ -0,0 +1,61 @@
+<?xml version="2.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.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/RootLayoutPadding"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+        <ListView
+            android:id="@id/android:list"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"/>
+
+        <TextView
+            android:id="@id/android:empty"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="1"
+            android:padding="10dip"
+            android:text="@string/da_no_policy"
+            android:textSize="18dip"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+            <Button
+                android:id="@+id/generate_policy_button"
+                android:layout_width="1dip"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/da_generate_policy"/>
+            <Button
+                android:id="@+id/apply_policy_button"
+                android:layout_width="1dip"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/da_apply_policy"/>
+        </LinearLayout>
+
+        <include layout="@layout/pass_fail_buttons"/>
+    </LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout-watch/requesting_bugreport_device_owner.xml b/apps/CtsVerifier/res/layout-watch/requesting_bugreport_device_owner.xml
new file mode 100644
index 0000000..4d4cf5d
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-watch/requesting_bugreport_device_owner.xml
@@ -0,0 +1,46 @@
+<?xml version="2.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.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/RootLayoutPadding"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/requesting_bugreport_device_owner_instructions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_owner_requesting_bugreport_tests_info"
+            android:textSize="18dip"/>
+
+        <Button
+            android:id="@+id/set_device_owner_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/set_device_owner_button_label"/>
+
+        <ListView
+            android:id="@+id/android:list"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+
+        <include layout="@layout/pass_fail_buttons"/>
+    </LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/da_policy_main.xml b/apps/CtsVerifier/res/layout/da_policy_main.xml
index 0f680e9..70e277b 100644
--- a/apps/CtsVerifier/res/layout/da_policy_main.xml
+++ b/apps/CtsVerifier/res/layout/da_policy_main.xml
@@ -1,60 +1,50 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2011 The Android Open Source Project
-
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
 -->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/RootLayoutPadding"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <LinearLayout
+    android:layout_height="match_parent"
+>
+    <ListView android:id="@id/android:list"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
-        <ListView
-            android:id="@id/android:list"
-            android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+    />
+    <TextView android:id="@id/android:empty"
+        android:layout_gravity="center_vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:padding="10dip"
+        android:text="@string/da_no_policy"
+        android:textSize="18dip"
+    />
+    <LinearLayout android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+    >
+        <Button android:id="@+id/generate_policy_button"
+            android:layout_width="1dip"
             android:layout_height="wrap_content"
-            android:layout_weight="1" />
-
-        <TextView
-            android:id="@id/android:empty"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
             android:layout_weight="1"
-            android:padding="10dip"
-            android:text="@string/da_no_policy"
-            android:textSize="18dip" />
-
-        <LinearLayout
-            android:layout_width="match_parent"
+            android:text="@string/da_generate_policy"
+        />
+        <Button android:id="@+id/apply_policy_button"
+            android:layout_width="1dip"
             android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <Button
-                android:id="@+id/generate_policy_button"
-                android:layout_width="1dip"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="@string/da_generate_policy" />
-            <Button
-                android:id="@+id/apply_policy_button"
-                android:layout_width="1dip"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="@string/da_apply_policy" />
-        </LinearLayout>
-
-        <include layout="@layout/pass_fail_buttons" />
+            android:layout_weight="1"
+            android:text="@string/da_apply_policy"
+        />
     </LinearLayout>
-</ScrollView>
+    <include layout="@layout/pass_fail_buttons"/>
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/requesting_bugreport_device_owner.xml b/apps/CtsVerifier/res/layout/requesting_bugreport_device_owner.xml
index b83388b..f3320c6 100644
--- a/apps/CtsVerifier/res/layout/requesting_bugreport_device_owner.xml
+++ b/apps/CtsVerifier/res/layout/requesting_bugreport_device_owner.xml
@@ -1,11 +1,9 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2016 The Android Open Source Project
-
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
@@ -13,38 +11,31 @@
      limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/RootLayoutPadding"
+    android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
-
+>
     <ScrollView
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        <LinearLayout
+        android:layout_height="100dp"
+        android:layout_weight="2">
+        <TextView
+            android:id="@+id/requesting_bugreport_device_owner_instructions"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical">
-
-            <TextView
-                android:id="@+id/requesting_bugreport_device_owner_instructions"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:text="@string/device_owner_requesting_bugreport_tests_info"
-                android:textSize="18dip" />
-
-            <Button
-                android:id="@+id/set_device_owner_button"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:text="@string/set_device_owner_button_label" />
-
-            <ListView
-                android:id="@+id/android:list"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
-            <include layout="@layout/pass_fail_buttons" />
-        </LinearLayout>
+            android:layout_height="wrap_content"
+            android:padding="10dip"
+            android:text="@string/device_owner_requesting_bugreport_tests_info"
+            android:textSize="18dip" />
     </ScrollView>
+    <Button
+        android:id="@+id/set_device_owner_button"
+        android:layout_width="204dp"
+        android:layout_height="wrap_content"
+        android:text="@string/set_device_owner_button_label" />
+    <ListView
+        android:id="@+id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="3" />
+    <include layout="@layout/pass_fail_buttons" />
 </LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 2f19c9c..35f0101 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1694,7 +1694,7 @@
         2. If \'Cts Verifier\' is not allowed to install apps, a warning dialog will appear
         blocking the install. In this case go to step 3, else skip to step 4.\n
         3. Allow \'Cts Verifier\' to install apps. Return to package installer.\n
-        4. Accept the package and verify that it installs.
+        4. Accept the installation and verify that it succeeds (no error message is displayed).
     </string>
 
     <string name="provisioning_byod_nonmarket_deny">Disable non-market apps</string>
@@ -1757,6 +1757,66 @@
     <string name="provisioning_byod_lockscreen_bound_key">Lockscreen-bound key test</string>
     <string name="provisioning_byod_fingerprint_bound_key">Fingerprint-bound key test</string>
     <string name="provisioning_byod_vpn">VPN test</string>
+    <string name="provisioning_byod_always_on_vpn">Always-on VPN Settings</string>
+    <string name="provisioning_byod_always_on_vpn_info">
+        In this test, you\'ll verify that the Settings UI for always-on VPN is correct for different
+        VPN apps.
+    </string>
+    <string name="provisioning_byod_always_on_vpn_instruction">
+        In this test, you\'ll verify the Settings UI for always-on VPN for different VPN apps.
+        You should have received three VPN app apks with this CTS Verifier package.
+        They\'re named in the form of \"CtsVpnFirewallApp*.apk\".\n
+
+        1. Before the test, make sure CtsVpnFirewallApp isn\'t installed on your device. You can
+           uninstall either by UI, or by\n
+           \"adb uninstall com.android.cts.vpnfirewall\"\n
+
+        2. Install the first test app, by running\n
+           \"adb install /path/to/CtsVpnFirewallAppApi23.apk\"\n
+
+        3. Tap \"Prepare VPN\" button below and consent to the VPN connection.\n
+
+        4. Finish all three test cases listed below.\n
+
+        5. Repeat step 1 to remove CtsVpnFirewallApp.
+    </string>
+    <string name="provisioning_byod_always_on_vpn_prepare_button">Prepare VPN</string>
+    <string name="provisioning_byod_always_on_vpn_vpn_not_found_note">
+        Can\'t find VPN app. Did you install it correctly?
+    </string>
+    <string name="provisioning_byod_always_on_vpn_api23">VPN app targeting SDK 23</string>
+    <string name="provisioning_byod_always_on_vpn_api23_instruction">
+        1. Re-install CtsVpnFirewallAppApi23.apk (skip this if you already have the correct version
+           installed):\n
+           \"adb install -r /path/to/CtsVpnFirewallAppApi23.apk\"\n
+        2. Tap \"Go\" button below to go to the VPN settings page.\n
+        3. Open configuration details page for CtsVpnFirewallApp.\n
+        4. Confirm the \"Always-on VPN\" and \"Block connections without VPN\" switches are both off
+           and disabled.\n
+    </string>
+    <string name="provisioning_byod_always_on_vpn_api24">VPN app targeting SDK 24</string>
+    <string name="provisioning_byod_always_on_vpn_api24_instruction">
+        1. Re-install CtsVpnFirewallAppApi24.apk (skip this if you already have the correct version
+           installed):\n
+           \"adb install -r /path/to/CtsVpnFirewallAppApi24.apk\"\n
+        2. Tap \"Go\" button below to go to the VPN settings page.\n
+        3. Open configuration details page for CtsVpnFirewallApp.\n
+        4. Confirm\n
+           4.1. \"Always-on VPN\" switch is enabled and in off position\n
+           4.2. \"Block connections without VPN\" switch is disabled and in off position\n
+           4.3. \"Block connections without VPN\" becomes enabled once the \"Always-on VPN\" switch
+                is turned on\n
+    </string>
+    <string name="provisioning_byod_always_on_vpn_not_always_on">VPN app with opt-out</string>
+    <string name="provisioning_byod_always_on_vpn_not_always_on_instruction">
+        1. Re-install CtsVpnFirewallAppNotAlwaysOn.apk (skip this if you already have the correct
+           version installed):\n
+           \"adb install -r /path/to/CtsVpnFirewallAppNotAlwaysOn.apk\"\n
+        2. Tap \"Go\" button below to go to the VPN settings page.\n
+        3. Open configuration details page for CtsVpnFirewallApp.\n
+        4. Confirm the \"Always-on VPN\" and \"Block connections without VPN\" switches are both off
+           and disabled.\n
+    </string>
     <string name="provisioning_byod_select_work_challenge">Select work lock test</string>
     <string name="provisioning_byod_select_work_challenge_description">
         This test verifies that a work lock can be chosen.\n
@@ -1953,7 +2013,9 @@
     <string name="device_admin_keyguard_disable_camera_instruction">
         Please press the Go button to lock the screen. Then try to open the camera
         from the lower right corner of the screen. Expected result is you cannot
-        open the camera from lock screen and it will ask for password instead.
+        open the camera from lock screen and it will ask for password instead.\n
+        Also, it shouldn\'t be possible to open the camera on the lockscreen by
+        any other device specific gesture (such as double press on power button).
     </string>
     <string name="device_admin_disable_notifications">Disable notifications</string>
     <string name="device_admin_disable_notifications_instruction">
@@ -2421,6 +2483,9 @@
         5. Verify that the background color of the resulting dialog is as set by you.\n
         6. Verify that the header text has organization name as set by you.\n
     </string>
+
+    <string name="provisioning_byod_no_secure_lockscreen">No work lockscreen password set. Please run \"Select work lock test\" and rerun this test</string>
+
     <string name="provisioning_byod_parent_profile_password">Personal password test</string>
     <string name="provisioning_byod_parent_profile_password_description">
         This test verifies that the password on the personal side can be chosen from within a managed profile.\n
@@ -2550,7 +2615,7 @@
     <string name="device_owner_reenable_statusbar_button">Reenable status bar</string>
     <string name="device_owner_disable_keyguard_test">Disable keyguard</string>
     <string name="device_owner_disable_keyguard_test_info">
-            Note that any device passwords that you might have set will be deleted during this test.\n
+            Before running this test, please make sure you have not set any device lockscreen password.\n
             Please press the below button to disable the keyguard. Press the power button on your device to
             switch off the screen. Then press the power button to switch the screen back on and verify that
             no keyguard was shown.\n
@@ -2560,6 +2625,7 @@
     </string>
     <string name="device_owner_disable_keyguard_button">Disable keyguard</string>
     <string name="device_owner_reenable_keyguard_button">Reenable keyguard</string>
+    <string name="device_owner_lockscreen_secure">Please remove lockscreen password</string>
     <string name="device_profile_owner_permission_lockdown_test">Permissions lockdown</string>
     <string name="device_profile_owner_permission_lockdown_test_instructions">
             Select each of the three grant states for the permission shown below in turn.\n
@@ -2859,7 +2925,7 @@
     <string name="disallow_outgoing_beam">Disallow outgoing beam</string>
     <string name="disallow_outgoing_beam_action">Switching on android beam</string>
     <string name="disallow_remove_user">Disallow remove user</string>
-    <string name="disallow_remove_user_action">Removing other users</string>
+    <string name="disallow_remove_user_action">Removing other users (please create a user and attempt to remove it to verify)</string>
     <string name="disallow_remove_managed_profile">Disallow remove managed profile</string>
     <string name="disallow_remove_managed_profile_action">Removing the work profile. It shouldn\'t be possible neither from the Accounts screen nor the Device Administrators screen (after selecting the Device Administrator that corresponds to the badged version of \"CTS Verifier\")</string>
     <string name="disallow_share_location">Disallow share location</string>
diff --git a/apps/CtsVerifier/res/xml/accessory_filter.xml b/apps/CtsVerifier/res/xml/accessory_filter.xml
index 4a1d779..ee25a0e 100644
--- a/apps/CtsVerifier/res/xml/accessory_filter.xml
+++ b/apps/CtsVerifier/res/xml/accessory_filter.xml
@@ -14,5 +14,6 @@
      limitations under the License.
 -->
 <resources>
-    <usb-accessory />
+    <usb-accessory manufacturer="Android CTS" model="Android CTS test companion device"
+        version="2" />
 </resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AlwaysOnVpnSettingsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AlwaysOnVpnSettingsTestActivity.java
new file mode 100644
index 0000000..011473c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AlwaysOnVpnSettingsTestActivity.java
@@ -0,0 +1,87 @@
+/*
+ * 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.cts.verifier.managedprovisioning;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.R;
+
+/**
+ * Tests the Settings UI for always-on VPN in the work profile.
+ */
+public class AlwaysOnVpnSettingsTestActivity extends DialogTestListActivity {
+
+    public static final String ACTION_ALWAYS_ON_VPN_SETTINGS_TEST =
+            "com.android.cts.verifier.managedprovisioning.action.ALWAYS_ON_VPN_SETTINGS_TEST";
+
+    private static final Intent VPN_SETTINGS_INTENT = new Intent(Settings.ACTION_VPN_SETTINGS);
+    private static final String CTS_VPN_APP_PACKAGE = "com.android.cts.vpnfirewall";
+    private static final String CTS_VPN_APP_ACTION =
+            "com.android.cts.vpnfirewall.action.CONNECT_AND_FINISH";
+
+    public AlwaysOnVpnSettingsTestActivity() {
+        super(R.layout.provisioning_byod,
+                R.string.provisioning_byod_always_on_vpn,
+                R.string.provisioning_byod_always_on_vpn_info,
+                R.string.provisioning_byod_always_on_vpn_instruction);
+    }
+
+    @Override
+    protected void setupTests(ArrayTestListAdapter adapter) {
+        adapter.add(new DialogTestListItem(this,
+                R.string.provisioning_byod_always_on_vpn_api23,
+                "BYOD_AlwaysOnVpnSettingsApi23Test",
+                R.string.provisioning_byod_always_on_vpn_api23_instruction,
+                VPN_SETTINGS_INTENT
+        ));
+        adapter.add(new DialogTestListItem(this,
+                R.string.provisioning_byod_always_on_vpn_api24,
+                "BYOD_AlwaysOnVpnSettingsApi24Test",
+                R.string.provisioning_byod_always_on_vpn_api24_instruction,
+                VPN_SETTINGS_INTENT
+        ));
+        adapter.add(new DialogTestListItem(this,
+                R.string.provisioning_byod_always_on_vpn_not_always_on,
+                "BYOD_AlwaysOnVpnSettingsNotAlwaysOnTest",
+                R.string.provisioning_byod_always_on_vpn_not_always_on_instruction,
+                VPN_SETTINGS_INTENT
+        ));
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mPrepareTestButton.setText(
+                R.string.provisioning_byod_always_on_vpn_prepare_button);
+        mPrepareTestButton.setOnClickListener(v -> {
+            try {
+                final Intent intent =
+                        getPackageManager().getLaunchIntentForPackage(CTS_VPN_APP_PACKAGE);
+                intent.setAction(CTS_VPN_APP_ACTION);
+                startActivity(intent);
+            } catch (ActivityNotFoundException unused) {
+                Utils.showToast(this, R.string.provisioning_byod_always_on_vpn_vpn_not_found_note);
+            }
+        });
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index 570c19e..3cf3516 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -101,6 +101,7 @@
     private DialogTestListItem mConfirmWorkCredentials;
     private DialogTestListItem mParentProfilePassword;
     private TestListItem mVpnTest;
+    private TestListItem mAlwaysOnVpnSettingsTest;
     private TestListItem mRecentsTest;
     private TestListItem mDisallowAppsControlTest;
     private TestListItem mOrganizationInfoTest;
@@ -353,6 +354,12 @@
                 new Intent(VpnTestActivity.ACTION_VPN),
                 null);
 
+        mAlwaysOnVpnSettingsTest = TestListItem.newTest(this,
+                R.string.provisioning_byod_always_on_vpn,
+                AlwaysOnVpnSettingsTestActivity.class.getName(),
+                new Intent(AlwaysOnVpnSettingsTestActivity.ACTION_ALWAYS_ON_VPN_SETTINGS_TEST),
+                null);
+
         mDisallowAppsControlTest = TestListItem.newTest(this,
                 R.string.provisioning_byod_disallow_apps_control,
                 DisallowAppsControlActivity.class.getName(),
@@ -452,6 +459,7 @@
         adapter.add(mKeyguardDisabledFeaturesTest);
         adapter.add(mAuthenticationBoundKeyTest);
         adapter.add(mVpnTest);
+        adapter.add(mAlwaysOnVpnSettingsTest);
         adapter.add(mTurnOffWorkFeaturesTest);
         adapter.add(mSelectWorkChallenge);
         adapter.add(mConfirmWorkCredentials);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
index d1308ad..5053a90 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
@@ -39,6 +39,7 @@
                 PermissionLockdownTestActivity.ACTIVITY_ALIAS,
                 AuthenticationBoundKeyTestActivity.class.getName(),
                 VpnTestActivity.class.getName(),
+                AlwaysOnVpnSettingsTestActivity.class.getName(),
                 RecentsRedactionActivity.class.getName(),
                 CommandReceiverActivity.class.getName(),
                 SetSupportMessageActivity.class.getName()
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index e9b6523..48323a7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -351,7 +351,11 @@
             KeyguardManager keyguardManager =
                     (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
             Intent launchIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, null);
-            startActivity(launchIntent);
+            if (launchIntent != null) {
+                startActivity(launchIntent);
+            } else {
+                showToast(R.string.provisioning_byod_no_secure_lockscreen);
+            }
         } else if (ACTION_SET_ORGANIZATION_INFO.equals(action)) {
             if(intent.hasExtra(OrganizationInfoTestActivity.EXTRA_ORGANIZATION_NAME)) {
                 final String organizationName = intent
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 6f98241..5ecb1ef 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -35,6 +36,7 @@
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.util.Log;
+import android.widget.Toast;
 
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.managedprovisioning.Utils;
@@ -206,10 +208,13 @@
                 } break;
                 case COMMAND_SET_KEYGUARD_DISABLED: {
                     boolean enforced = intent.getBooleanExtra(EXTRA_ENFORCED, false);
-                    if (enforced) {
-                        mDpm.resetPassword(null, 0);
+                    KeyguardManager km = this.getSystemService(KeyguardManager.class);
+                    if (km.isKeyguardSecure()) {
+                        Toast.makeText(this, getString(R.string.device_owner_lockscreen_secure),
+                                Toast.LENGTH_SHORT).show();
+                    } else {
+                        mDpm.setKeyguardDisabled(mAdmin, enforced);
                     }
-                    mDpm.setKeyguardDisabled(mAdmin, enforced);
                 } break;
                 case COMMAND_SET_STATUSBAR_DISABLED: {
                     boolean enforced = intent.getBooleanExtra(EXTRA_ENFORCED, false);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 1c40ac1..f54e567 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -110,6 +110,7 @@
         filter.addAction(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST);
         filter.addAction(ByodHelperActivity.ACTION_BYOD_SET_LOCATION_AND_CHECK_UPDATES);
         filter.addAction(VpnTestActivity.ACTION_VPN);
+        filter.addAction(AlwaysOnVpnSettingsTestActivity.ACTION_ALWAYS_ON_VPN_SETTINGS_TEST);
         filter.addAction(RecentsRedactionActivity.ACTION_RECENTS);
         filter.addAction(ByodHelperActivity.ACTION_TEST_SELECT_WORK_CHALLENGE);
         filter.addAction(ByodHelperActivity.ACTION_LAUNCH_CONFIRM_WORK_CREDENTIALS);
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 23744c7..7cfa040 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
@@ -32,7 +32,6 @@
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.service.notification.NotificationListenerService;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -47,7 +46,7 @@
 
 public class AttentionManagementVerifierActivity
         extends InteractiveVerifierActivity {
-    private static final String TAG = "NoListenerAttentionVerifier";
+    private static final String TAG = "AttentionVerifier";
 
     private static final String NOTIFICATION_CHANNEL_ID = TAG;
     private static final String NOTIFICATION_CHANNEL_ID_NOISY = TAG + "/noisy";
@@ -92,12 +91,8 @@
         tests.add(new IsEnabledTest());
         tests.add(new ServiceStartedTest());
         tests.add(new InsertContactsTest());
-        tests.add(new SetModeNoneTest());
         tests.add(new NoneInterceptsAllTest());
-        tests.add(new SetModeAllTest());
-        tests.add(new SetModePriorityTest());
         tests.add(new PriorityInterceptsSomeTest());
-        tests.add(new SetModeAllTest());
         tests.add(new AllInterceptsNothingTest());
         tests.add(new DefaultOrderTest());
         tests.add(new PriorityOrderTest());
@@ -139,8 +134,6 @@
             insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
             // charlie is not in contacts
             status = READY;
-            // wait for insertions to move through the system
-            delay();
         }
 
         @Override
@@ -157,7 +150,6 @@
             if (status == PASS && !isStarred(mAliceUri)) {
                 status = RETEST;
                 Log.i("InsertContactsTest", "Alice is not yet starred");
-                delay();
             } else {
                 Log.i("InsertContactsTest", "Alice is: " + mAliceUri);
                 Log.i("InsertContactsTest", "Bob is: " + mBobUri);
@@ -193,37 +185,6 @@
         }
     }
 
-    protected class SetModeNoneTest extends InteractiveTestCase {
-        @Override
-        View inflate(ViewGroup parent) {
-            return createRetryItem(parent, R.string.attention_filter_none);
-        }
-
-        @Override
-        void test() {
-            MockListener.probeFilter(mContext,
-                    new MockListener.IntegerResultCatcher() {
-                        @Override
-                        public void accept(int mode) {
-                            if (mode == NotificationListenerService.INTERRUPTION_FILTER_NONE) {
-                                status = PASS;
-                                next();
-                            } else {
-                                Log.i("SetModeNoneTest", "waiting, current mode is: " + mode);
-                                status = WAIT_FOR_USER;
-                            }
-                        }
-                    });
-        }
-
-        @Override
-        void tearDown() {
-            mNm.cancelAll();
-            MockListener.resetListenerData(mContext);
-            delay();
-        }
-    }
-
     protected class NoneInterceptsAllTest extends InteractiveTestCase {
         @Override
         View inflate(ViewGroup parent) {
@@ -232,92 +193,59 @@
 
         @Override
         void setUp() {
+            mNm.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
             createChannels();
             sendNotifications(MODE_URI, false, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerPayloads(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> result) {
-                            Set<String> found = new HashSet<String>();
-                            if (result == null || result.size() == 0) {
-                                status = FAIL;
-                                next();
-                                return;
-                            }
-                            boolean pass = true;
-                            for (String payloadData : result) {
-                                try {
-                                    JSONObject payload = new JSONObject(payloadData);
-                                    String tag = payload.getString(JSON_TAG);
-                                    boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
-                                    Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
-                                    if (found.contains(tag)) {
-                                        // multiple entries for same notification!
-                                        pass = false;
-                                    } else if (ALICE.equals(tag)) {
-                                        found.add(ALICE);
-                                        pass &= !zen;
-                                    } else if (BOB.equals(tag)) {
-                                        found.add(BOB);
-                                        pass &= !zen;
-                                    } else if (CHARLIE.equals(tag)) {
-                                        found.add(CHARLIE);
-                                        pass &= !zen;
-                                    }
-                                } catch (JSONException e) {
-                                    pass = false;
-                                    Log.e(TAG, "failed to unpack data from mocklistener", e);
-                                }
-                            }
-                            pass &= found.size() == 3;
-                            status = pass ? PASS : FAIL;
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<JSONObject> result = new ArrayList<>(MockListener.getInstance().getPosted());
+
+            Set<String> found = new HashSet<String>();
+            if (result.size() == 0) {
+                status = FAIL;
+                return;
+            }
+            boolean pass = true;
+            for (JSONObject payload : result) {
+                try {
+                    String tag = payload.getString(JSON_TAG);
+                    boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
+                    Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
+                    if (found.contains(tag)) {
+                        // multiple entries for same notification!
+                        pass = false;
+                    } else if (ALICE.equals(tag)) {
+                        found.add(ALICE);
+                        pass &= !zen;
+                    } else if (BOB.equals(tag)) {
+                        found.add(BOB);
+                        pass &= !zen;
+                    } else if (CHARLIE.equals(tag)) {
+                        found.add(CHARLIE);
+                        pass &= !zen;
+                    }
+                } catch (JSONException e) {
+                    pass = false;
+                    Log.e(TAG, "failed to unpack data from mocklistener", e);
+                }
+            }
+            pass &= found.size() == 3;
+            status = pass ? PASS : FAIL;
         }
 
         @Override
         void tearDown() {
+            mNm.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
 
     }
 
-    protected class SetModeAllTest extends InteractiveTestCase {
-        @Override
-        View inflate(ViewGroup parent) {
-            return createRetryItem(parent, R.string.attention_filter_all);
-        }
-
-        @Override
-        void test() {
-            MockListener.probeFilter(mContext,
-                    new MockListener.IntegerResultCatcher() {
-                        @Override
-                        public void accept(int mode) {
-                            if (mode == NotificationListenerService.INTERRUPTION_FILTER_ALL) {
-                                status = PASS;
-                                next();
-                            } else {
-                                Log.i("SetModeAllTest", "waiting, current mode is: " + mode);
-                                status = WAIT_FOR_USER;
-                            }
-                        }
-                    });
-        }
-    }
-
     protected class AllInterceptsNothingTest extends InteractiveTestCase {
         @Override
         View inflate(ViewGroup parent) {
@@ -329,84 +257,50 @@
             createChannels();
             sendNotifications(MODE_URI, false, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerPayloads(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> result) {
-                            Set<String> found = new HashSet<String>();
-                            if (result == null || result.size() == 0) {
-                                status = FAIL;
-                                return;
-                            }
-                            boolean pass = true;
-                            for (String payloadData : result) {
-                                try {
-                                    JSONObject payload = new JSONObject(payloadData);
-                                    String tag = payload.getString(JSON_TAG);
-                                    boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
-                                    Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
-                                    if (found.contains(tag)) {
-                                        // multiple entries for same notification!
-                                        pass = false;
-                                    } else if (ALICE.equals(tag)) {
-                                        found.add(ALICE);
-                                        pass &= zen;
-                                    } else if (BOB.equals(tag)) {
-                                        found.add(BOB);
-                                        pass &= zen;
-                                    } else if (CHARLIE.equals(tag)) {
-                                        found.add(CHARLIE);
-                                        pass &= zen;
-                                    }
-                                } catch (JSONException e) {
-                                    pass = false;
-                                    Log.e(TAG, "failed to unpack data from mocklistener", e);
-                                }
-                            }
-                            pass &= found.size() == 3;
-                            status = pass ? PASS : FAIL;
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<JSONObject> result = new ArrayList<>(MockListener.getInstance().getPosted());
+
+            Set<String> found = new HashSet<String>();
+            if (result.size() == 0) {
+                status = FAIL;
+                return;
+            }
+            boolean pass = true;
+            for (JSONObject payload : result) {
+                try {
+                    String tag = payload.getString(JSON_TAG);
+                    boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
+                    Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
+                    if (found.contains(tag)) {
+                        // multiple entries for same notification!
+                        pass = false;
+                    } else if (ALICE.equals(tag)) {
+                        found.add(ALICE);
+                        pass &= zen;
+                    } else if (BOB.equals(tag)) {
+                        found.add(BOB);
+                        pass &= zen;
+                    } else if (CHARLIE.equals(tag)) {
+                        found.add(CHARLIE);
+                        pass &= zen;
+                    }
+                } catch (JSONException e) {
+                    pass = false;
+                    Log.e(TAG, "failed to unpack data from mocklistener", e);
+                }
+            }
+            pass &= found.size() == 3;
+            status = pass ? PASS : FAIL;
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
-        }
-    }
-
-    protected class SetModePriorityTest extends InteractiveTestCase {
-        @Override
-        View inflate(ViewGroup parent) {
-            return createRetryItem(parent, R.string.attention_filter_priority);
-        }
-
-        @Override
-        void test() {
-            MockListener.probeFilter(mContext,
-                    new MockListener.IntegerResultCatcher() {
-                        @Override
-                        public void accept(int mode) {
-                            if (mode == NotificationListenerService.INTERRUPTION_FILTER_PRIORITY) {
-                                status = PASS;
-                                next();
-                            } else {
-                                Log.i("SetModePriorityTest", "waiting, current mode is: " + mode);
-                                status = WAIT_FOR_USER;
-                            }
-                        }
-                    });
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -418,63 +312,60 @@
 
         @Override
         void setUp() {
+            mNm.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
+            NotificationManager.Policy policy = mNm.getNotificationPolicy();
+            policy = new NotificationManager.Policy(policy.priorityCategories,
+                    policy.priorityCallSenders,
+                    NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
+            mNm.setNotificationPolicy(policy);
             createChannels();
             sendNotifications(MODE_URI, false, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerPayloads(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> result) {
-                            Set<String> found = new HashSet<String>();
-                            if (result == null || result.size() == 0) {
-                                status = FAIL;
-                                return;
-                            }
-                            boolean pass = true;
-                            for (String payloadData : result) {
-                                try {
-                                    JSONObject payload = new JSONObject(payloadData);
-                                    String tag = payload.getString(JSON_TAG);
-                                    boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
-                                    Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
-                                    if (found.contains(tag)) {
-                                        // multiple entries for same notification!
-                                        pass = false;
-                                    } else if (ALICE.equals(tag)) {
-                                        found.add(ALICE);
-                                        pass &= zen;
-                                    } else if (BOB.equals(tag)) {
-                                        found.add(BOB);
-                                        pass &= !zen;
-                                    } else if (CHARLIE.equals(tag)) {
-                                        found.add(CHARLIE);
-                                        pass &= !zen;
-                                    }
-                                } catch (JSONException e) {
-                                    pass = false;
-                                    Log.e(TAG, "failed to unpack data from mocklistener", e);
-                                }
-                            }
-                            pass &= found.size() == 3;
-                            status = pass ? PASS : FAIL;
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<JSONObject> result = new ArrayList<>(MockListener.getInstance().getPosted());
+
+            Set<String> found = new HashSet<String>();
+            if (result.size() == 0) {
+                status = FAIL;
+                return;
+            }
+            boolean pass = true;
+            for (JSONObject payload : result) {
+                try {
+                    String tag = payload.getString(JSON_TAG);
+                    boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
+                    Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
+                    if (found.contains(tag)) {
+                        // multiple entries for same notification!
+                        pass = false;
+                    } else if (ALICE.equals(tag)) {
+                        found.add(ALICE);
+                        pass &= zen;
+                    } else if (BOB.equals(tag)) {
+                        found.add(BOB);
+                        pass &= !zen;
+                    } else if (CHARLIE.equals(tag)) {
+                        found.add(CHARLIE);
+                        pass &= !zen;
+                    }
+                } catch (JSONException e) {
+                    pass = false;
+                    Log.e(TAG, "failed to unpack data from mocklistener", e);
+                }
+            }
+            pass &= found.size() == 3;
+            status = pass ? PASS : FAIL;
         }
 
         @Override
         void tearDown() {
+            mNm.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -490,37 +381,27 @@
             createChannels();
             sendNotifications(MODE_NONE, false, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerOrder(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> orderedKeys) {
-                            int rankA = findTagInKeys(ALICE, orderedKeys);
-                            int rankB = findTagInKeys(BOB, orderedKeys);
-                            int rankC = findTagInKeys(CHARLIE, orderedKeys);
-                            if (rankC < rankB && rankB < rankA) {
-                                status = PASS;
-                            } else {
-                                logFail(rankA + ", " + rankB + ", " + rankC);
-                                status = FAIL;
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<String> orderedKeys = new ArrayList<>(MockListener.getInstance().mOrder);
+            int rankA = findTagInKeys(ALICE, orderedKeys);
+            int rankB = findTagInKeys(BOB, orderedKeys);
+            int rankC = findTagInKeys(CHARLIE, orderedKeys);
+            if (rankC < rankB && rankB < rankA) {
+                status = PASS;
+            } else {
+                logFail(rankA + ", " + rankB + ", " + rankC);
+                status = FAIL;
+            }
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -536,37 +417,27 @@
             createChannels();
             sendNotifications(MODE_NONE, true, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerOrder(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> orderedKeys) {
-                            int rankA = findTagInKeys(ALICE, orderedKeys);
-                            int rankB = findTagInKeys(BOB, orderedKeys);
-                            int rankC = findTagInKeys(CHARLIE, orderedKeys);
-                            if (rankB < rankC && rankC < rankA) {
-                                status = PASS;
-                            } else {
-                                logFail(rankA + ", " + rankB + ", " + rankC);
-                                status = FAIL;
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<String> orderedKeys = new ArrayList<>(MockListener.getInstance().mOrder);
+            int rankA = findTagInKeys(ALICE, orderedKeys);
+            int rankB = findTagInKeys(BOB, orderedKeys);
+            int rankC = findTagInKeys(CHARLIE, orderedKeys);
+            if (rankB < rankC && rankC < rankA) {
+                status = PASS;
+            } else {
+                logFail(rankA + ", " + rankB + ", " + rankC);
+                status = FAIL;
+            }
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -581,59 +452,50 @@
 
         @Override
         void setUp() {
+            delayTime = 15000;
             createChannels();
             // send B & C noisy with contact affinity
-            sendNotifications(SEND_B | SEND_C, MODE_URI, false, true);
-            status = READY;
-            // wait for then to not be recently noisy any more
-            delay(15000);
+            sendNotifications(SEND_B, MODE_URI, false, true);
+            sleep(1000);
+            sendNotifications(SEND_C, MODE_URI, false, true);
+            status = READY_AFTER_LONG_DELAY;
         }
 
         @Override
         void test() {
-            if (status == READY) {
+            if (status == READY_AFTER_LONG_DELAY) {
                 // send A noisy but no contact affinity
                 sendNotifications(SEND_A, MODE_NONE, false, true);
                 status = RETEST;
-                delay();
-            } else if (status == RETEST) {
-                MockListener.probeListenerOrder(mContext,
-                        new MockListener.StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> orderedKeys) {
-                                int rankA = findTagInKeys(ALICE, orderedKeys);
-                                int rankB = findTagInKeys(BOB, orderedKeys);
-                                int rankC = findTagInKeys(CHARLIE, orderedKeys);
-                                if (!mSawElevation) {
-                                    if (rankA < rankB && rankA < rankC) {
-                                        mSawElevation = true;
-                                        status = RETEST;
-                                        delay(15000);
-                                    } else {
-                                        logFail("noisy notification did not sort to top.");
-                                        status = FAIL;
-                                        next();
-                                    }
-                                } else {
-                                    if (rankA > rankB && rankA > rankC) {
-                                        status = PASS;
-                                    } else {
-                                        logFail("noisy notification did not fade back into the list.");
-                                        status = FAIL;
-                                    }
-                                }
-                            }
-                        });
-                delay();  // in case the catcher never returns
-           }
+            } else if (status == RETEST || status == RETEST_AFTER_LONG_DELAY) {
+                List<String> orderedKeys = new ArrayList<>(MockListener.getInstance().mOrder);
+                int rankA = findTagInKeys(ALICE, orderedKeys);
+                int rankB = findTagInKeys(BOB, orderedKeys);
+                int rankC = findTagInKeys(CHARLIE, orderedKeys);
+                if (!mSawElevation) {
+                    if (rankA < rankB && rankA < rankC) {
+                        mSawElevation = true;
+                        status = RETEST_AFTER_LONG_DELAY;
+                    } else {
+                        logFail("noisy notification did not sort to top.");
+                        status = FAIL;
+                    }
+                } else {
+                    if (rankA > rankB && rankA > rankC) {
+                        status = PASS;
+                    } else {
+                        logFail("noisy notification did not fade back into the list.");
+                        status = FAIL;
+                    }
+                }
+            }
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -650,60 +512,50 @@
             sendNotifications(SEND_B | SEND_C, MODE_NONE, true, true);
             sendNotifications(SEND_A, MODE_NONE, true, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerPayloads(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> result) {
-                            Set<String> found = new HashSet<String>();
-                            if (result == null || result.size() == 0) {
-                                status = FAIL;
-                                return;
-                            }
-                            boolean pass = true;
-                            for (String payloadData : result) {
-                                try {
-                                    JSONObject payload = new JSONObject(payloadData);
-                                    String tag = payload.getString(JSON_TAG);
-                                    boolean ambient = payload.getBoolean(JSON_AMBIENT);
-                                    Log.e(TAG, tag + (ambient ? " is" : " isn't") + " ambient");
-                                    if (found.contains(tag)) {
-                                        // multiple entries for same notification!
-                                        pass = false;
-                                    } else if (ALICE.equals(tag)) {
-                                        found.add(ALICE);
-                                        pass &= ambient;
-                                    } else if (BOB.equals(tag)) {
-                                        found.add(BOB);
-                                        pass &= !ambient;
-                                    } else if (CHARLIE.equals(tag)) {
-                                        found.add(CHARLIE);
-                                        pass &= !ambient;
-                                    }
-                                } catch (JSONException e) {
-                                    pass = false;
-                                    Log.e(TAG, "failed to unpack data from mocklistener", e);
-                                }
-                            }
-                            pass &= found.size() == 3;
-                            status = pass ? PASS : FAIL;
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<JSONObject> result = new ArrayList<>(MockListener.getInstance().getPosted());
+
+            Set<String> found = new HashSet<String>();
+            if (result.size() == 0) {
+                status = FAIL;
+                return;
+            }
+            boolean pass = true;
+            for (JSONObject payload : result) {
+                try {
+                    String tag = payload.getString(JSON_TAG);
+                    boolean ambient = payload.getBoolean(JSON_AMBIENT);
+                    Log.e(TAG, tag + (ambient ? " is" : " isn't") + " ambient");
+                    if (found.contains(tag)) {
+                        // multiple entries for same notification!
+                        pass = false;
+                    } else if (ALICE.equals(tag)) {
+                        found.add(ALICE);
+                        pass &= ambient;
+                    } else if (BOB.equals(tag)) {
+                        found.add(BOB);
+                        pass &= !ambient;
+                    } else if (CHARLIE.equals(tag)) {
+                        found.add(CHARLIE);
+                        pass &= !ambient;
+                    }
+                } catch (JSONException e) {
+                    pass = false;
+                    Log.e(TAG, "failed to unpack data from mocklistener", e);
+                }
+            }
+            pass &= found.size() == 3;
+            status = pass ? PASS : FAIL;
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -719,37 +571,27 @@
             createChannels();
             sendNotifications(MODE_URI, false, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerOrder(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> orderedKeys) {
-                            int rankA = findTagInKeys(ALICE, orderedKeys);
-                            int rankB = findTagInKeys(BOB, orderedKeys);
-                            int rankC = findTagInKeys(CHARLIE, orderedKeys);
-                            if (rankA < rankB && rankB < rankC) {
-                                status = PASS;
-                            } else {
-                                logFail(rankA + ", " + rankB + ", " + rankC);
-                                status = FAIL;
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<String> orderedKeys = new ArrayList<>(MockListener.getInstance().mOrder);
+            int rankA = findTagInKeys(ALICE, orderedKeys);
+            int rankB = findTagInKeys(BOB, orderedKeys);
+            int rankC = findTagInKeys(CHARLIE, orderedKeys);
+            if (rankA < rankB && rankB < rankC) {
+                status = PASS;
+            } else {
+                logFail(rankA + ", " + rankB + ", " + rankC);
+                status = FAIL;
+            }
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -765,37 +607,27 @@
             createChannels();
             sendNotifications(MODE_EMAIL, false, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerOrder(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> orderedKeys) {
-                            int rankA = findTagInKeys(ALICE, orderedKeys);
-                            int rankB = findTagInKeys(BOB, orderedKeys);
-                            int rankC = findTagInKeys(CHARLIE, orderedKeys);
-                            if (rankA < rankB && rankB < rankC) {
-                                status = PASS;
-                            } else {
-                                logFail(rankA + ", " + rankB + ", " + rankC);
-                                status = FAIL;
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<String> orderedKeys = new ArrayList<>(MockListener.getInstance().mOrder);
+            int rankA = findTagInKeys(ALICE, orderedKeys);
+            int rankB = findTagInKeys(BOB, orderedKeys);
+            int rankC = findTagInKeys(CHARLIE, orderedKeys);
+            if (rankA < rankB && rankB < rankC) {
+                status = PASS;
+            } else {
+                logFail(rankA + ", " + rankB + ", " + rankC);
+                status = FAIL;
+            }
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -811,37 +643,27 @@
             createChannels();
             sendNotifications(MODE_PHONE, false, false);
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerOrder(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> orderedKeys) {
-                            int rankA = findTagInKeys(ALICE, orderedKeys);
-                            int rankB = findTagInKeys(BOB, orderedKeys);
-                            int rankC = findTagInKeys(CHARLIE, orderedKeys);
-                            if (rankA < rankB && rankB < rankC) {
-                                status = PASS;
-                            } else {
-                                logFail(rankA + ", " + rankB + ", " + rankC);
-                                status = FAIL;
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<String> orderedKeys = new ArrayList<>(MockListener.getInstance().mOrder);
+            int rankA = findTagInKeys(ALICE, orderedKeys);
+            int rankB = findTagInKeys(BOB, orderedKeys);
+            int rankC = findTagInKeys(CHARLIE, orderedKeys);
+            if (rankA < rankB && rankB < rankC) {
+                status = PASS;
+            } else {
+                logFail(rankA + ", " + rankB + ", " + rankC);
+                status = FAIL;
+            }
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannels();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
index 24d88b7..f3bf7e5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
@@ -88,9 +88,7 @@
                 logFail("no settings activity");
                 status = FAIL;
             } else {
-                String cpPackages = Secure.getString(getContentResolver(),
-                        Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
-                if (cpPackages != null && cpPackages.contains(CP_PACKAGE)) {
+                if (mNm.isNotificationPolicyAccessGranted()) {
                     status = PASS;
                 } else {
                     status = WAIT_FOR_USER;
@@ -505,9 +503,7 @@
 
         @Override
         void test() {
-            String cpPackages = Secure.getString(getContentResolver(),
-                    Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
-            if (cpPackages == null || !cpPackages.contains(CP_PACKAGE)) {
+            if (!mNm.isNotificationPolicyAccessGranted()) {
                 status = PASS;
             } else {
                 status = WAIT_FOR_USER;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
index de3b050..7d5de8c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.cts.verifier.notifications;
 
-import android.app.Activity;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -59,6 +58,8 @@
     protected static final int PASS = 3;
     protected static final int FAIL = 4;
     protected static final int WAIT_FOR_USER = 5;
+    protected static final int RETEST_AFTER_LONG_DELAY = 6;
+    protected static final int READY_AFTER_LONG_DELAY = 7;
 
     protected static final int NOTIFICATION_ID = 1001;
 
@@ -95,6 +96,7 @@
     protected abstract class InteractiveTestCase {
         int status;
         private View view;
+        protected long delayTime = 3000;
 
         abstract View inflate(ViewGroup parent);
         View getView(ViewGroup parent) {
@@ -127,7 +129,7 @@
                     ((message == null) ? "" : ": " + message));
         }
 
-        protected void logFail(String message, Exception e) {
+        protected void logFail(String message, Throwable e) {
             Log.e(TAG, "failed " + this.getClass().getSimpleName() +
                     ((message == null) ? "" : ": " + message), e);
         }
@@ -261,22 +263,35 @@
             case SETUP:
                 Log.i(TAG, "running setup for: " + mCurrentTest.getClass().getSimpleName());
                 mCurrentTest.setUp();
+                if (mCurrentTest.status == READY_AFTER_LONG_DELAY) {
+                    delay(mCurrentTest.delayTime);
+                } else {
+                    delay();
+                }
                 break;
 
             case WAIT_FOR_USER:
                 Log.i(TAG, "waiting for user: " + mCurrentTest.getClass().getSimpleName());
                 break;
 
+            case READY_AFTER_LONG_DELAY:
+            case RETEST_AFTER_LONG_DELAY:
             case READY:
             case RETEST:
                 Log.i(TAG, "running test for: " + mCurrentTest.getClass().getSimpleName());
                 mCurrentTest.test();
+                if (mCurrentTest.status == RETEST_AFTER_LONG_DELAY) {
+                    delay(mCurrentTest.delayTime);
+                } else {
+                    delay();
+                }
                 break;
 
             case FAIL:
                 Log.i(TAG, "FAIL: " + mCurrentTest.getClass().getSimpleName());
                 mCurrentTest.tearDown();
                 mCurrentTest = null;
+                delay();
                 break;
 
             case PASS:
@@ -285,6 +300,7 @@
                 if (mTestOrder.hasNext()) {
                     mCurrentTest = mTestOrder.next();
                     Log.i(TAG, "next test is: " + mCurrentTest.getClass().getSimpleName());
+                    next();
                 } else {
                     Log.i(TAG, "no more tests");
                     mCurrentTest = null;
@@ -466,27 +482,14 @@
 
         @Override
         void test() {
-            MockListener.probeListenerStatus(mContext,
-                    new MockListener.StatusCatcher() {
-                        @Override
-                        public void accept(int result) {
-                            if (result == Activity.RESULT_OK) {
-                                status = PASS;
-                                next();
-                            } else {
-                                logFail();
-                                status = RETEST;
-                                delay();
-                            }
-                        }
-                    });
-            delay();  // in case the catcher never returns
-        }
-
-        @Override
-        void tearDown() {
-            MockListener.resetListenerData(mContext);
-            delay();
+            if (MockListener.getInstance() != null) {
+                status = PASS;
+                next();
+            } else {
+                logFail();
+                status = RETEST;
+                delay();
+            }
         }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index d311faa..8b5acf8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -15,15 +15,8 @@
  */
 package com.android.cts.verifier.notifications;
 
-import android.app.Activity;
 import android.app.Notification;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.Parcelable;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
@@ -33,8 +26,8 @@
 import org.json.JSONObject;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 public class MockListener extends NotificationListenerService {
@@ -43,31 +36,6 @@
     public static final ComponentName COMPONENT_NAME =
             new ComponentName("com.android.cts.verifier", MockListener.class.getName());
 
-    static final String SERVICE_BASE = "android.service.notification.cts.";
-    static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
-    static final String SERVICE_POSTED = SERVICE_BASE + "SERVICE_POSTED";
-    static final String SERVICE_PAYLOADS = SERVICE_BASE + "SERVICE_PAYLOADS";
-    static final String SERVICE_REMOVED = SERVICE_BASE + "SERVICE_REMOVED";
-    static final String SERVICE_REMOVED_REASON = SERVICE_BASE + "SERVICE_REMOVED";
-    static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
-    static final String SERVICE_CLEAR_ONE = SERVICE_BASE + "SERVICE_CLEAR_ONE";
-    static final String SERVICE_CLEAR_ALL = SERVICE_BASE + "SERVICE_CLEAR_ALL";
-    static final String SERVICE_SNOOZE = SERVICE_BASE + "SERVICE_SNOOZE";
-    static final String SERVICE_HINTS = SERVICE_BASE + "SERVICE_HINTS";
-    static final String SERVICE_PROBE_HINTS = SERVICE_BASE + "SERVICE_PROBE_HINTS";
-    static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
-    static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
-    static final String SERVICE_SNOOZE_DURATION = SERVICE_BASE + "SERVICE_SNOOZE_DURATION";
-    static final String SERVICE_GET_SNOOZED = SERVICE_BASE + "GET_SNOOZED";
-
-    static final String EXTRA_PAYLOAD = "PAYLOAD";
-    static final String EXTRA_POSTED_NOTIFICATIONS = "NOTIFICATION_PAYLOAD";
-    static final String EXTRA_INT = "INT";
-    static final String EXTRA_TAG = "TAG";
-    static final String EXTRA_CODE = "CODE";
-    static final String EXTRA_LONG = "LONG";
-
-    static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
 
     public static final String JSON_FLAGS = "flag";
     public static final String JSON_ICON = "icon";
@@ -79,19 +47,19 @@
     public static final String JSON_AMBIENT = "ambient";
     public static final String JSON_MATCHES_ZEN_FILTER = "matches_zen_filter";
     public static final String JSON_REASON = "reason";
-    public static final String JSON_HINTS = "hints";
 
-    private ArrayList<String> mPosted = new ArrayList<String>();
-    private ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
-    private ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
-    private ArrayList<String> mRemoved = new ArrayList<String>();
-    private ArrayMap<String, JSONObject> mRemovedReason = new ArrayMap<>();
-    private ArrayList<String> mSnoozed = new ArrayList<>();
-    private ArrayList<String> mOrder = new ArrayList<>();
-    private Set<String> mTestPackages = new HashSet<>();
-    private BroadcastReceiver mReceiver;
-    private int mDND = -1;
-    private ArrayList<Notification> mPostedNotifications = new ArrayList<Notification>();
+    ArrayList<String> mPosted = new ArrayList<String>();
+    ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
+    ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
+    ArrayList<String> mRemoved = new ArrayList<String>();
+    ArrayMap<String, JSONObject> mRemovedReason = new ArrayMap<>();
+    ArrayList<String> mSnoozed = new ArrayList<>();
+    ArrayList<String> mOrder = new ArrayList<>();
+    Set<String> mTestPackages = new HashSet<>();
+    int mDND = -1;
+    ArrayList<Notification> mPostedNotifications = new ArrayList<Notification>();
+    private static MockListener sNotificationListenerInstance = null;
+    boolean isConnected;
 
     @Override
     public void onCreate() {
@@ -100,119 +68,19 @@
 
         mTestPackages.add("com.android.cts.verifier");
         mTestPackages.add("com.android.cts.robot");
+    }
 
-        mPosted = new ArrayList<String>();
-        mRemoved = new ArrayList<String>();
-        mSnoozed = new ArrayList<String>();
-        mPostedNotifications = new ArrayList<Notification>();
+    protected Collection<JSONObject> getPosted() {
+        return mNotifications.values();
+    }
 
-        mReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final String action = intent.getAction();
-                final Bundle bundle = new Bundle();
-                Log.d(TAG, action);
-                if (SERVICE_CHECK.equals(action)) {
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_POSTED.equals(action)) {
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
-                    bundle.putParcelableArrayList(EXTRA_POSTED_NOTIFICATIONS, mPostedNotifications);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_DND.equals(action)) {
-                    bundle.putInt(EXTRA_INT, mDND);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_ORDER.equals(action)) {
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_PAYLOADS.equals(action)) {
-                    ArrayList<String> payloadData = new ArrayList<>(mNotifications.size());
-                    for (JSONObject payload: mNotifications.values()) {
-                        payloadData.add(payload.toString());
-                    }
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, payloadData);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_REMOVED.equals(action)) {
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_REMOVED_REASON.equals(action)) {
-                    ArrayList<String> payloadData = new ArrayList<>(mRemovedReason.size());
-                    for (JSONObject payload: mRemovedReason.values()) {
-                        payloadData.add(payload.toString());
-                    }
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, payloadData);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_CLEAR_ONE.equals(action)) {
-                    String tag = intent.getStringExtra(EXTRA_TAG);
-                    String key = mNotificationKeys.get(tag);
-                    if (key != null) {
-                        MockListener.this.cancelNotification(key);
-                    } else {
-                        Log.w(TAG, "Notification does not exist: " + tag);
-                    }
-                } else if (SERVICE_CLEAR_ALL.equals(action)) {
-                    MockListener.this.cancelAllNotifications();
-                } else if (SERVICE_RESET.equals(action)) {
-                    resetData();
-                } else if (SERVICE_SNOOZE.equals(action)) {
-                    MockListener.this.requestUnbind();
-                } else if (SERVICE_HINTS.equals(action)) {
-                    MockListener.this.requestListenerHints(intent.getIntExtra(EXTRA_CODE, 0));
-                } else if (SERVICE_PROBE_HINTS.equals(action)) {
-                    bundle.putInt(EXTRA_INT, MockListener.this.getCurrentListenerHints());
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_SNOOZE_DURATION.equals(action)) {
-                    String tag = intent.getStringExtra(EXTRA_TAG);
-                    String key = mNotificationKeys.get(tag);
-                    if (key != null) {
-                        MockListener.this.snoozeNotification(key,
-                                intent.getLongExtra(EXTRA_LONG, (long) 0));
-                    }
-                } else if (SERVICE_GET_SNOOZED.equals(action)) {
-                    mSnoozed.clear();
-                    StatusBarNotification[] snoozed = MockListener.this.getSnoozedNotifications();
-                    for (StatusBarNotification sbn : snoozed) {
-                        mSnoozed.add(sbn.getTag());
-                    }
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, mSnoozed);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else {
-                    Log.w(TAG, "unknown action");
-                    setResultCode(Activity.RESULT_CANCELED);
-                }
-            }
-        };
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(SERVICE_CHECK);
-        filter.addAction(SERVICE_DND);
-        filter.addAction(SERVICE_POSTED);
-        filter.addAction(SERVICE_ORDER);
-        filter.addAction(SERVICE_PAYLOADS);
-        filter.addAction(SERVICE_REMOVED);
-        filter.addAction(SERVICE_REMOVED_REASON);
-        filter.addAction(SERVICE_CLEAR_ONE);
-        filter.addAction(SERVICE_CLEAR_ALL);
-        filter.addAction(SERVICE_RESET);
-        filter.addAction(SERVICE_SNOOZE);
-        filter.addAction(SERVICE_HINTS);
-        filter.addAction(SERVICE_PROBE_HINTS);
-        filter.addAction(SERVICE_SNOOZE_DURATION);
-        filter.addAction(SERVICE_GET_SNOOZED);
-        registerReceiver(mReceiver, filter);
+    protected String getKeyForTag(String tag) {
+        return mNotificationKeys.get(tag);
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
-        unregisterReceiver(mReceiver);
-        mReceiver = null;
         Log.d(TAG, "destroyed");
     }
 
@@ -221,6 +89,13 @@
         super.onListenerConnected();
         mDND = getCurrentInterruptionFilter();
         Log.d(TAG, "initial value of CurrentInterruptionFilter is " + mDND);
+        sNotificationListenerInstance = this;
+        isConnected = true;
+    }
+
+    @Override
+    public void onListenerDisconnected() {
+        isConnected = false;
     }
 
     @Override
@@ -230,6 +105,10 @@
         Log.d(TAG, "value of CurrentInterruptionFilter changed to " + mDND);
     }
 
+    public static MockListener getInstance() {
+        return sNotificationListenerInstance;
+    }
+
     public void resetData() {
         mPosted.clear();
         mNotifications.clear();
@@ -296,7 +175,7 @@
     @Override
     public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
             int reason) {
-        Log.d(TAG, "removed: " + sbn.getTag());
+        Log.d(TAG, "removed: " + sbn.getTag() + " for reason " + reason);
         mRemoved.add(sbn.getTag());
         JSONObject removed = new JSONObject();
         try {
@@ -311,155 +190,4 @@
         onNotificationRankingUpdate(rankingMap);
     }
 
-    public static void resetListenerData(Context context) {
-        sendCommand(context, SERVICE_RESET, null, 0);
-    }
-
-    public static void probeListenerStatus(Context context, StatusCatcher catcher) {
-        requestStatus(context, SERVICE_CHECK, catcher);
-    }
-
-    public static void probeFilter(Context context, IntegerResultCatcher catcher) {
-        requestIntegerResult(context, SERVICE_DND, catcher);
-    }
-
-    public static void probeListenerPosted(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_POSTED, catcher);
-    }
-
-    public static void probeListenerPosted(Context context, NotificationResultCatcher catcher) {
-        requestNotificationResult(context, SERVICE_POSTED, catcher);
-    }
-
-    public static void probeListenerSnoozed(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_GET_SNOOZED, catcher);
-    }
-
-    public static void probeListenerOrder(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_ORDER, catcher);
-    }
-
-    public static void probeListenerPayloads(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_PAYLOADS, catcher);
-    }
-
-    public static void probeListenerRemoved(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_REMOVED, catcher);
-    }
-
-    public static void probeListenerRemovedWithReason(Context context,
-            StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_REMOVED_REASON, catcher);
-    }
-
-    public static void probeListenerHints(Context context, IntegerResultCatcher catcher) {
-        requestIntegerResult(context, SERVICE_PROBE_HINTS, catcher);
-    }
-
-    public static void setHints(Context context, int hints) {
-        Intent broadcast = new Intent(SERVICE_HINTS);
-        broadcast.putExtra(EXTRA_CODE, hints);
-        context.sendBroadcast(broadcast);
-    }
-
-    public static void snooze(Context context) {
-        sendCommand(context, SERVICE_SNOOZE, null, 0);
-    }
-
-    public static void clearOne(Context context, String tag, int code) {
-        sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
-    }
-
-    public static void snoozeOneFor(Context context, String tag, long duration) {
-        Intent broadcast = new Intent(SERVICE_SNOOZE_DURATION);
-        if (tag != null) {
-            broadcast.putExtra(EXTRA_TAG, tag);
-            broadcast.putExtra(EXTRA_LONG, duration);
-        }
-        context.sendBroadcast(broadcast);
-    }
-
-    public static void clearAll(Context context) {
-        sendCommand(context, SERVICE_CLEAR_ALL, null, 0);
-    }
-
-    private static void sendCommand(Context context, String action, String tag, int code) {
-        Intent broadcast = new Intent(action);
-        if (tag != null) {
-            broadcast.putExtra(EXTRA_TAG, tag);
-            broadcast.putExtra(EXTRA_CODE, code);
-        }
-        context.sendBroadcast(broadcast);
-    }
-
-    public abstract static class StatusCatcher extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            accept(Integer.valueOf(getResultCode()));
-        }
-
-        abstract public void accept(int result);
-    }
-
-    private static void requestStatus(Context context, String action,
-            StatusCatcher catcher) {
-        Intent broadcast = new Intent(action);
-        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
-    }
-
-    public abstract static class IntegerResultCatcher extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            accept(getResultExtras(true).getInt(EXTRA_INT, -1));
-        }
-
-        abstract public void accept(int result);
-    }
-
-    private static void requestIntegerResult(Context context, String action,
-            IntegerResultCatcher catcher) {
-        Intent broadcast = new Intent(action);
-        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
-    }
-
-    public abstract static class StringListResultCatcher extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            accept(getResultExtras(true).getStringArrayList(EXTRA_PAYLOAD));
-        }
-
-        abstract public void accept(List<String> result);
-    }
-
-    public abstract static class NotificationResultCatcher extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            ArrayList<Parcelable> parcels =
-                    getResultExtras(true).getParcelableArrayList(EXTRA_POSTED_NOTIFICATIONS);
-            if (parcels == null) {
-                parcels = new ArrayList<Parcelable>();
-            }
-            List<Notification> notifications = new ArrayList<Notification>(parcels.size());
-            for (Parcelable parcel : parcels) {
-                if (parcel instanceof Notification) {
-                    notifications.add((Notification) parcel);
-                }
-            }
-            accept(notifications);
-        }
-
-        abstract public void accept(List<Notification> result);
-    }
-
-    private static void requestStringListResult(Context context, String action,
-            StringListResultCatcher catcher) {
-        Intent broadcast = new Intent(action);
-        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
-    }
-
-    private static void requestNotificationResult(Context context, String action,
-            NotificationResultCatcher catcher) {
-        Intent broadcast = new Intent(action);
-        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
-    }
 }
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 20e7d1e..9f8438e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -21,7 +21,11 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
 import android.provider.Settings.Secure;
+import android.service.notification.StatusBarNotification;
 import android.support.v4.app.NotificationCompat;
 import android.util.Log;
 import android.view.View;
@@ -40,6 +44,8 @@
 
 import static com.android.cts.verifier.notifications.MockListener.*;
 
+import static junit.framework.Assert.assertNotNull;
+
 public class NotificationListenerVerifierActivity extends InteractiveVerifierActivity
         implements Runnable {
     private static final String TAG = "NoListenerVerifier";
@@ -78,7 +84,7 @@
         List<InteractiveTestCase> tests = new ArrayList<>(17);
         tests.add(new IsEnabledTest());
         tests.add(new ServiceStartedTest());
-        tests.add(new NotificationRecievedTest());
+        tests.add(new NotificationReceivedTest());
         tests.add(new DataIntactTest());
         tests.add(new DismissOneTest());
         tests.add(new DismissOneWithReasonTest());
@@ -87,8 +93,8 @@
         tests.add(new SnoozeNotificationForTimeCancelTest());
         tests.add(new GetSnoozedNotificationTest());
         tests.add(new EnableHintsTest());
-        tests.add(new SnoozeTest());
-        tests.add(new UnsnoozeTest());
+        tests.add(new RequestUnbindTest());
+        tests.add(new RequestBindTest());
         tests.add(new MessageBundleTest());
         tests.add(new EnableHintsTest());
         tests.add(new IsDisabledTest());
@@ -110,10 +116,11 @@
     @SuppressLint("NewApi")
     private void sendNotifications() {
         mTag1 = UUID.randomUUID().toString();
+        Log.d(TAG, "Sending " + mTag1);
         mTag2 = UUID.randomUUID().toString();
+        Log.d(TAG, "Sending " + mTag2);
         mTag3 = UUID.randomUUID().toString();
-
-        mNm.cancelAll();
+        Log.d(TAG, "Sending " + mTag3);
 
         mWhen1 = System.currentTimeMillis() + 1;
         mWhen2 = System.currentTimeMillis() + 2;
@@ -131,8 +138,7 @@
 
         Notification n1 = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setContentTitle("ClearTest 1")
-                .setContentText(mTag1.toString())
-                .setPriority(Notification.PRIORITY_LOW)
+                .setContentText(mTag1)
                 .setSmallIcon(mIcon1)
                 .setWhen(mWhen1)
                 .setDeleteIntent(makeIntent(1, mTag1))
@@ -143,8 +149,7 @@
 
         Notification n2 = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setContentTitle("ClearTest 2")
-                .setContentText(mTag2.toString())
-                .setPriority(Notification.PRIORITY_HIGH)
+                .setContentText(mTag2)
                 .setSmallIcon(mIcon2)
                 .setWhen(mWhen2)
                 .setDeleteIntent(makeIntent(2, mTag2))
@@ -155,8 +160,7 @@
 
         Notification n3 = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setContentTitle("ClearTest 3")
-                .setContentText(mTag3.toString())
-                .setPriority(Notification.PRIORITY_LOW)
+                .setContentText(mTag3)
                 .setSmallIcon(mIcon3)
                 .setWhen(mWhen3)
                 .setDeleteIntent(makeIntent(3, mTag3))
@@ -169,7 +173,7 @@
 
     // Tests
 
-    private class NotificationRecievedTest extends InteractiveTestCase {
+    private class NotificationReceivedTest extends InteractiveTestCase {
         @Override
         View inflate(ViewGroup parent) {
             return createAutoItem(parent, R.string.nls_note_received);
@@ -181,34 +185,24 @@
             createChannel();
             sendNotifications();
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
             deleteChannel();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerPosted(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> result) {
-                            if (result != null && result.size() > 0 && result.contains(mTag1)) {
-                                status = PASS;
-                            } else {
-                                logFail();
-                                status = FAIL;
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
+            if (result.size() > 0 && result.contains(mTag1)) {
+                status = PASS;
+            } else {
+                logFail();
+                status = FAIL;
+            }
         }
     }
 
@@ -223,81 +217,73 @@
             createChannel();
             sendNotifications();
             status = READY;
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerPayloads(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> result) {
-                            Set<String> found = new HashSet<String>();
-                            if (result == null || result.size() == 0) {
-                                status = FAIL;
-                                return;
-                            }
-                            boolean pass = true;
-                            for (String payloadData : result) {
-                                try {
-                                    JSONObject payload = new JSONObject(payloadData);
-                                    pass &= checkEquals(mPackageString,
-                                            payload.getString(JSON_PACKAGE),
-                                            "data integrity test: notification package (%s, %s)");
-                                    String tag = payload.getString(JSON_TAG);
-                                    if (mTag1.equals(tag)) {
-                                        found.add(mTag1);
-                                        pass &= checkEquals(mIcon1, payload.getInt(JSON_ICON),
-                                                "data integrity test: notification icon (%d, %d)");
-                                        pass &= checkFlagSet(mFlag1, payload.getInt(JSON_FLAGS),
-                                                "data integrity test: notification flags (%d, %d)");
-                                        pass &= checkEquals(mId1, payload.getInt(JSON_ID),
-                                                "data integrity test: notification ID (%d, %d)");
-                                        pass &= checkEquals(mWhen1, payload.getLong(JSON_WHEN),
-                                                "data integrity test: notification when (%d, %d)");
-                                    } else if (mTag2.equals(tag)) {
-                                        found.add(mTag2);
-                                        pass &= checkEquals(mIcon2, payload.getInt(JSON_ICON),
-                                                "data integrity test: notification icon (%d, %d)");
-                                        pass &= checkFlagSet(mFlag2, payload.getInt(JSON_FLAGS),
-                                                "data integrity test: notification flags (%d, %d)");
-                                        pass &= checkEquals(mId2, payload.getInt(JSON_ID),
-                                                "data integrity test: notification ID (%d, %d)");
-                                        pass &= checkEquals(mWhen2, payload.getLong(JSON_WHEN),
-                                                "data integrity test: notification when (%d, %d)");
-                                    } else if (mTag3.equals(tag)) {
-                                        found.add(mTag3);
-                                        pass &= checkEquals(mIcon3, payload.getInt(JSON_ICON),
-                                                "data integrity test: notification icon (%d, %d)");
-                                        pass &= checkFlagSet(mFlag3, payload.getInt(JSON_FLAGS),
-                                                "data integrity test: notification flags (%d, %d)");
-                                        pass &= checkEquals(mId3, payload.getInt(JSON_ID),
-                                                "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;
-                                    Log.e(TAG, "failed to unpack data from mocklistener", e);
-                                }
-                            }
+            List<JSONObject> result = new ArrayList<>(MockListener.getInstance().getPosted());
 
-                            pass &= found.size() == 3;
-                            status = pass ? PASS : FAIL;
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            Set<String> found = new HashSet<String>();
+            if (result.size() == 0) {
+                status = FAIL;
+                return;
+            }
+            boolean pass = true;
+            for (JSONObject payload : result) {
+                try {
+                    pass &= checkEquals(mPackageString,
+                            payload.getString(JSON_PACKAGE),
+                            "data integrity test: notification package (%s, %s)");
+                    String tag = payload.getString(JSON_TAG);
+                    if (mTag1.equals(tag)) {
+                        found.add(mTag1);
+                        pass &= checkEquals(mIcon1, payload.getInt(JSON_ICON),
+                                "data integrity test: notification icon (%d, %d)");
+                        pass &= checkFlagSet(mFlag1, payload.getInt(JSON_FLAGS),
+                                "data integrity test: notification flags (%d, %d)");
+                        pass &= checkEquals(mId1, payload.getInt(JSON_ID),
+                                "data integrity test: notification ID (%d, %d)");
+                        pass &= checkEquals(mWhen1, payload.getLong(JSON_WHEN),
+                                "data integrity test: notification when (%d, %d)");
+                    } else if (mTag2.equals(tag)) {
+                        found.add(mTag2);
+                        pass &= checkEquals(mIcon2, payload.getInt(JSON_ICON),
+                                "data integrity test: notification icon (%d, %d)");
+                        pass &= checkFlagSet(mFlag2, payload.getInt(JSON_FLAGS),
+                                "data integrity test: notification flags (%d, %d)");
+                        pass &= checkEquals(mId2, payload.getInt(JSON_ID),
+                                "data integrity test: notification ID (%d, %d)");
+                        pass &= checkEquals(mWhen2, payload.getLong(JSON_WHEN),
+                                "data integrity test: notification when (%d, %d)");
+                    } else if (mTag3.equals(tag)) {
+                        found.add(mTag3);
+                        pass &= checkEquals(mIcon3, payload.getInt(JSON_ICON),
+                                "data integrity test: notification icon (%d, %d)");
+                        pass &= checkFlagSet(mFlag3, payload.getInt(JSON_FLAGS),
+                                "data integrity test: notification flags (%d, %d)");
+                        pass &= checkEquals(mId3, payload.getInt(JSON_ID),
+                                "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;
+                    Log.e(TAG, "failed to unpack data from mocklistener", e);
+                }
+            }
+
+            pass &= found.size() == 3;
+            status = pass ? PASS : FAIL;
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
+            deleteChannel();
         }
     }
 
@@ -312,45 +298,39 @@
             createChannel();
             sendNotifications();
             status = READY;
-            delay();
         }
 
         @Override
         void test() {
             if (status == READY) {
-                MockListener.clearOne(mContext, mTag1, mId1);
+                MockListener.getInstance().cancelNotification(
+                        MockListener.getInstance().getKeyForTag(mTag1));
                 status = RETEST;
             } else {
-                MockListener.probeListenerRemoved(mContext,
-                        new MockListener.StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result != null && result.size() != 0
-                                        && result.contains(mTag1)
-                                        && !result.contains(mTag2)
-                                        && !result.contains(mTag3)) {
-                                    status = PASS;
-                                } else {
-                                    logFail();
-                                    status = FAIL;
-                                }
-                                next();
-                            }
-                        });
+                List<String> result = new ArrayList<>(MockListener.getInstance().mRemoved);
+                if (result.size() != 0
+                        && result.contains(mTag1)
+                        && !result.contains(mTag2)
+                        && !result.contains(mTag3)) {
+                    status = PASS;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
             }
-            delay();
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannel();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
     private class DismissOneWithReasonTest extends InteractiveTestCase {
+        int mRetries = 3;
+
         @Override
         View inflate(ViewGroup parent) {
             return createAutoItem(parent, R.string.nls_clear_one_reason);
@@ -361,52 +341,51 @@
             createChannel();
             sendNotifications();
             status = READY;
-            delay();
         }
 
         @Override
         void test() {
             if (status == READY) {
-                MockListener.clearOne(mContext, mTag1, mId1);
+                MockListener.getInstance().cancelNotification(
+                        MockListener.getInstance().getKeyForTag(mTag1));
                 status = RETEST;
             } else {
-                MockListener.probeListenerRemovedWithReason(mContext,
-                        new StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result == null || result.size() == 0) {
-                                    status = FAIL;
-                                    return;
-                                }
-                                boolean pass = true;
-                                for (String payloadData : result) {
-                                    JSONObject payload = null;
-                                    try {
-                                        payload = new JSONObject(payloadData);
-                                        pass &= checkEquals(mTag1,
-                                                payload.getString(JSON_TAG),
-                                                "data dismissal test: notification tag (%s, %s)");
-                                        pass &= checkEquals(REASON_LISTENER_CANCEL,
-                                                payload.getInt(JSON_TAG),
-                                                "data dismissal test: reason (%d, %d)");
-                                    } catch (JSONException e) {
-                                        e.printStackTrace();
-                                    }
-                                }
-                                status = pass ? PASS : FAIL;
-                                next();
-                            }
-                        });
+                List<JSONObject> result =
+                        new ArrayList<>(MockListener.getInstance().mRemovedReason.values());
+                boolean pass = false;
+                for (JSONObject payload : result) {
+                    try {
+                        pass |= (checkEquals(mTag1,
+                                payload.getString(JSON_TAG),
+                                "data dismissal test: notification tag (%s, %s)")
+                                && checkEquals(REASON_LISTENER_CANCEL,
+                                payload.getInt(JSON_REASON),
+                                "data dismissal test: reason (%d, %d)"));
+                        if(pass) {
+                            break;
+                        }
+                    } catch (JSONException e) {
+                        e.printStackTrace();
+                    }
+                }
+                if (pass) {
+                    status = PASS;
+                } else {
+                    if (--mRetries > 0) {
+                        sleep(100);
+                        status = RETEST;
+                    } else {
+                        status = FAIL;
+                    }
+                }
             }
-            delay();
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannel();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -421,41 +400,32 @@
             createChannel();
             sendNotifications();
             status = READY;
-            delay();
         }
 
         @Override
         void test() {
             if (status == READY) {
-                MockListener.clearAll(mContext);
+                MockListener.getInstance().cancelAllNotifications();
                 status = RETEST;
             } else {
-                MockListener.probeListenerRemoved(mContext,
-                        new MockListener.StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result != null && result.size() != 0
-                                        && result.contains(mTag1)
-                                        && result.contains(mTag2)
-                                        && result.contains(mTag3)) {
-                                    status = PASS;
-                                } else {
-                                    logFail();
-                                    status = FAIL;
-                                }
-                                next();
-                            }
-                        });
+                List<String> result = new ArrayList<>(MockListener.getInstance().mRemoved);
+                if (result.size() != 0
+                        && result.contains(mTag1)
+                        && result.contains(mTag2)
+                        && result.contains(mTag3)) {
+                    status = PASS;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
             }
-            delay();  // in case the catcher never returns
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannel();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -471,12 +441,6 @@
         }
 
         @Override
-        void setUp(){
-            MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
-            delay();
-        }
-
-        @Override
         void test() {
             String listeners = Secure.getString(getContentResolver(),
                     ENABLED_NOTIFICATION_LISTENERS);
@@ -485,13 +449,11 @@
             } else {
                 status = WAIT_FOR_USER;
             }
-            next();
         }
 
         @Override
         void tearDown() {
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -503,30 +465,11 @@
 
         @Override
         void test() {
-            MockListener.probeListenerStatus(mContext,
-                    new MockListener.StatusCatcher() {
-                        @Override
-                        public void accept(int result) {
-                            if (result == Activity.RESULT_OK) {
-                                logFail();
-                                status = FAIL;
-                            } else {
-                                if (mNm.getEffectsSuppressor() == null) {
-                                    status = PASS;
-                                } else {
-                                    status = FAIL;
-                                }
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
-        }
-
-        @Override
-        void tearDown() {
-            // wait for intent to move through the system
-            delay();
+            if (mNm.getEffectsSuppressor() == null) {
+                status = PASS;
+            } else {
+                status = FAIL;
+            }
         }
     }
 
@@ -542,37 +485,31 @@
             createChannel();
             sendNotifications();
             status = READY;
-            delay();
         }
 
         @Override
         void test() {
-            MockListener.probeListenerPosted(mContext,
-                    new MockListener.StringListResultCatcher() {
-                        @Override
-                        public void accept(List<String> result) {
-                            if (result == null || result.size() == 0) {
-                                status = PASS;
-                            } else {
-                                logFail();
-                                status = FAIL;
-                            }
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
+            if (result.size() == 0) {
+                status = PASS;
+            } else {
+                logFail();
+                status = FAIL;
+            }
+            next();
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannel();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
-    private class SnoozeTest extends InteractiveTestCase {
+    private class RequestUnbindTest extends InteractiveTestCase {
+        int mRetries = 5;
+
         @Override
         View inflate(ViewGroup parent) {
             return createAutoItem(parent, R.string.nls_snooze);
@@ -582,46 +519,34 @@
         @Override
         void setUp() {
             status = READY;
-            MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
-            delay();
+            MockListener.getInstance().requestInterruptionFilter(
+                    MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
         }
 
         @Override
         void test() {
             if (status == READY) {
-                MockListener.snooze(mContext);
+                MockListener.getInstance().requestUnbind();
                 status = RETEST;
             } else {
-                MockListener.probeListenerStatus(mContext,
-                        new MockListener.StatusCatcher() {
-                            @Override
-                            public void accept(int result) {
-                                if (result == Activity.RESULT_OK) {
-                                    logFail();
-                                    status = FAIL;
-                                } else {
-                                    if (mNm.getEffectsSuppressor() == null) {
-                                        status = PASS;
-                                    } else {
-                                        logFail();
-                                        status = RETEST;
-                                        delay();
-                                    }
-                                }
-                                next();
-                            }
-                        });
+                if (mNm.getEffectsSuppressor() == null && !MockListener.getInstance().isConnected) {
+                    status = PASS;
+                } else {
+                    if (--mRetries > 0) {
+                        status = RETEST;
+                    } else {
+                        logFail();
+                        status = FAIL;
+                    }
+                }
+                next();
             }
-            delay();  // in case the catcher never returns
-        }
-
-        @Override
-        void tearDown() {
-            delay();
         }
     }
 
-    private class UnsnoozeTest extends InteractiveTestCase {
+    private class RequestBindTest extends InteractiveTestCase {
+        int mRetries = 5;
+
         @Override
         View inflate(ViewGroup parent) {
             return createAutoItem(parent, R.string.nls_unsnooze);
@@ -629,38 +554,24 @@
         }
 
         @Override
-        void setUp() {
-            status = READY;
-            delay();
-        }
-
-        @Override
         void test() {
             if (status == READY) {
                 MockListener.requestRebind(MockListener.COMPONENT_NAME);
                 status = RETEST;
             } else {
-                MockListener.probeListenerStatus(mContext,
-                        new MockListener.StatusCatcher() {
-                            @Override
-                            public void accept(int result) {
-                                if (result == Activity.RESULT_OK) {
-                                    status = PASS;
-                                    next();
-                                } else {
-                                    logFail();
-                                    status = RETEST;
-                                    delay();
-                                }
-                            }
-                        });
+                if (MockListener.getInstance().isConnected) {
+                    status = PASS;
+                    next();
+                } else {
+                    if (--mRetries > 0) {
+                        status = RETEST;
+                        next();
+                    } else {
+                        logFail();
+                        status = FAIL;
+                    }
+                }
             }
-            delay();  // in case the catcher never returns
-        }
-
-        @Override
-        void tearDown() {
-            delay();
         }
     }
 
@@ -672,37 +583,21 @@
         }
 
         @Override
-        void setUp() {
-            status = READY;
-            delay();
-        }
-
-        @Override
         void test() {
             if (status == READY) {
-                MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+                MockListener.getInstance().requestListenerHints(
+                        MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
                 status = RETEST;
             } else {
-                MockListener.probeListenerHints(mContext,
-                        new MockListener.IntegerResultCatcher() {
-                            @Override
-                            public void accept(int result) {
-                                if (result == MockListener.HINT_HOST_DISABLE_CALL_EFFECTS) {
-                                    status = PASS;
-                                } else {
-                                    logFail();
-                                    status = FAIL;
-                                }
-                                next();
-                            }
-                        });
+                int result = MockListener.getInstance().getCurrentListenerHints();
+                if (result == MockListener.HINT_HOST_DISABLE_CALL_EFFECTS) {
+                    status = PASS;
+                    next();
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
             }
-            delay();  // in case the catcher never returns
-        }
-
-        @Override
-        void tearDown() {
-            delay();
         }
     }
 
@@ -712,6 +607,7 @@
         final static int READY_TO_CHECK_FOR_UNSNOOZE = 2;
         int state = -1;
         long snoozeTime = 3000;
+
         @Override
         View inflate(ViewGroup parent) {
             return createAutoItem(parent, R.string.nls_snooze_one_time);
@@ -730,66 +626,52 @@
         void test() {
             status = RETEST;
             if (state == READY_TO_SNOOZE) {
-                MockListener.snoozeOneFor(mContext, mTag1, snoozeTime);
+                MockListener.getInstance().snoozeNotification(
+                        MockListener.getInstance().getKeyForTag(mTag1), snoozeTime);
                 state = SNOOZED;
-            } else if (state == SNOOZED){
-                MockListener.probeListenerRemovedWithReason(mContext,
-                        new StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result == null || result.size() == 0) {
-                                    status = FAIL;
-                                    return;
-                                }
-                                boolean pass = true;
-                                for (String payloadData : result) {
-                                    JSONObject payload = null;
-                                    try {
-                                        payload = new JSONObject(payloadData);
-                                        pass &= checkEquals(mTag1,
-                                                payload.getString(JSON_TAG),
-                                                "data dismissal test: notification tag (%s, %s)");
-                                        pass &= checkEquals(MockListener.REASON_SNOOZED,
-                                                payload.getInt(JSON_TAG),
-                                                "data dismissal test: reason (%d, %d)");
-                                    } catch (JSONException e) {
-                                        e.printStackTrace();
-                                    }
-                                }
-                                if (!pass) {
-                                    logFail();
-                                    status = FAIL;
-                                    next();
-                                    return;
-                                } else {
-                                    state = READY_TO_CHECK_FOR_UNSNOOZE;
-                                }
-                            }
-                        });
+            } else if (state == SNOOZED) {
+                List<JSONObject> result =
+                        new ArrayList<>(MockListener.getInstance().mRemovedReason.values());
+                boolean pass = false;
+                for (JSONObject payload : result) {
+                    try {
+                        pass |= (checkEquals(mTag1,
+                                payload.getString(JSON_TAG),
+                                "data dismissal test: notification tag (%s, %s)")
+                                && checkEquals(MockListener.REASON_SNOOZED,
+                                payload.getInt(JSON_REASON),
+                                "data dismissal test: reason (%d, %d)"));
+                        if (pass) {
+                            break;
+                        }
+                    } catch (JSONException e) {
+                        e.printStackTrace();
+                    }
+                }
+                if (!pass) {
+                    logFail();
+                    status = FAIL;
+                    next();
+                    return;
+                } else {
+                    state = READY_TO_CHECK_FOR_UNSNOOZE;
+                }
             } else {
-                MockListener.probeListenerPosted(mContext,
-                        new MockListener.StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result != null && result.size() != 0
-                                        && result.contains(mTag1)) {
-                                    status = PASS;
-                                } else {
-                                    logFail();
-                                    status = FAIL;
-                                }
-                                next();
-                            }
-                        });
+                List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
+                if (result.size() > 0 && result.contains(mTag1)) {
+                    status = PASS;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
             }
-            delay();
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannel();
-            MockListener.resetListenerData(mContext);
+            MockListener.getInstance().resetData();
             delay();
         }
     }
@@ -806,6 +688,7 @@
         int state = -1;
         long snoozeTime = 10000;
         private String tag;
+
         @Override
         View inflate(ViewGroup parent) {
             return createAutoItem(parent, R.string.nls_snooze_one_time);
@@ -825,51 +708,46 @@
         void test() {
             status = RETEST;
             if (state == READY_TO_SNOOZE) {
-                MockListener.snoozeOneFor(mContext, tag, snoozeTime);
+                MockListener.getInstance().snoozeNotification(
+                        MockListener.getInstance().getKeyForTag(tag), snoozeTime);
                 state = SNOOZED;
-            } else if (state == SNOOZED){
-                MockListener.probeListenerSnoozed(mContext,
-                        new MockListener.StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result != null && result.size() >= 1
-                                        && result.contains(tag)) {
-                                    // cancel and repost
-                                    sendNotifications();
-                                    state = READY_TO_CHECK_FOR_SNOOZE;
-                                    delay();
-                                } else {
-                                    logFail();
-                                    status = FAIL;
-                                    next();
-                                }
-                            }
-                        });
+            } else if (state == SNOOZED) {
+                List<String> result = getSnoozed();
+                if (result.size() >= 1
+                        && result.contains(tag)) {
+                    // cancel and repost
+                    sendNotifications();
+                    state = READY_TO_CHECK_FOR_SNOOZE;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
             } else {
-                MockListener.probeListenerSnoozed(mContext,
-                        new MockListener.StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result != null && result.size() >= 1
-                                        && result.contains(tag)) {
-                                    status = PASS;
-                                } else {
-                                    logFail();
-                                    status = FAIL;
-                                }
-                                next();
-                            }
-                        });
+                List<String> result = getSnoozed();
+                if (result.size() >= 1
+                        && result.contains(tag)) {
+                    status = PASS;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
             }
-            delay();
+        }
+
+        private List<String> getSnoozed() {
+            List<String> result = new ArrayList<>();
+            StatusBarNotification[] snoozed = MockListener.getInstance().getSnoozedNotifications();
+            for (StatusBarNotification sbn : snoozed) {
+                result.add(sbn.getTag());
+            }
+            return result;
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannel();
-            MockListener.resetListenerData(mContext);
-            delay();
+            MockListener.getInstance().resetData();
         }
     }
 
@@ -879,6 +757,7 @@
         final static int READY_TO_CHECK_FOR_GET_SNOOZE = 2;
         int state = -1;
         long snoozeTime = 30000;
+
         @Override
         View inflate(ViewGroup parent) {
             return createAutoItem(parent, R.string.nls_get_snoozed);
@@ -890,75 +769,69 @@
             sendNotifications();
             status = READY;
             state = READY_TO_SNOOZE;
-            delay();
         }
 
         @Override
         void test() {
             status = RETEST;
             if (state == READY_TO_SNOOZE) {
-                MockListener.snoozeOneFor(mContext, mTag1, snoozeTime);
-                MockListener.snoozeOneFor(mContext, mTag2, snoozeTime);
+                MockListener.getInstance().snoozeNotification(
+                        MockListener.getInstance().getKeyForTag(mTag1), snoozeTime);
+                MockListener.getInstance().snoozeNotification(
+                        MockListener.getInstance().getKeyForTag(mTag2), snoozeTime);
                 state = SNOOZED;
-            } else if (state == SNOOZED){
-                MockListener.probeListenerRemovedWithReason(mContext,
-                        new StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result == null || result.size() == 0) {
-                                    status = FAIL;
-                                    return;
-                                }
-                                boolean pass = true;
-                                for (String payloadData : result) {
-                                    JSONObject payload = null;
-                                    try {
-                                        payload = new JSONObject(payloadData);
-                                        pass &= checkEquals(mTag1,
-                                                payload.getString(JSON_TAG),
-                                                "data dismissal test: notification tag (%s, %s)");
-                                        pass &= checkEquals(MockListener.REASON_SNOOZED,
-                                                payload.getInt(JSON_TAG),
-                                                "data dismissal test: reason (%d, %d)");
-                                    } catch (JSONException e) {
-                                        e.printStackTrace();
-                                    }
-                                }
-                                if (!pass) {
-                                    logFail();
-                                    status = FAIL;
-                                    next();
-                                    return;
-                                } else {
-                                    state = READY_TO_CHECK_FOR_GET_SNOOZE;
-                                }
-                            }
-                        });
+            } else if (state == SNOOZED) {
+                List<JSONObject> result =
+                        new ArrayList<>(MockListener.getInstance().mRemovedReason.values());
+                if (result.size() == 0) {
+                    status = FAIL;
+                    return;
+                }
+                boolean pass = false;
+                for (JSONObject payload : result) {
+                    try {
+                        pass |= (checkEquals(mTag1,
+                                payload.getString(JSON_TAG),
+                                "data dismissal test: notification tag (%s, %s)")
+                                && checkEquals(MockListener.REASON_SNOOZED,
+                                payload.getInt(JSON_REASON),
+                                "data dismissal test: reason (%d, %d)"));
+                        if (pass) {
+                            break;
+                        }
+                    } catch (JSONException e) {
+                        e.printStackTrace();
+                    }
+                }
+                if (!pass) {
+                    logFail();
+                    status = FAIL;
+                } else {
+                    state = READY_TO_CHECK_FOR_GET_SNOOZE;
+                }
             } else {
-                MockListener.probeListenerSnoozed(mContext,
-                        new MockListener.StringListResultCatcher() {
-                            @Override
-                            public void accept(List<String> result) {
-                                if (result != null && result.size() >= 2
-                                        && result.contains(mTag1)
-                                        && result.contains(mTag2)) {
-                                    status = PASS;
-                                } else {
-                                    logFail();
-                                    status = FAIL;
-                                }
-                                next();
-                            }
-                        });
+                List<String> result = new ArrayList<>();
+                StatusBarNotification[] snoozed =
+                        MockListener.getInstance().getSnoozedNotifications();
+                for (StatusBarNotification sbn : snoozed) {
+                    result.add(sbn.getTag());
+                }
+                if (result.size() >= 2
+                        && result.contains(mTag1)
+                        && result.contains(mTag2)) {
+                    status = PASS;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
             }
-            delay();
         }
 
         @Override
         void tearDown() {
             mNm.cancelAll();
             deleteChannel();
-            MockListener.resetListenerData(mContext);
+            MockListener.getInstance().resetData();
             delay();
         }
     }
@@ -980,12 +853,11 @@
             createChannel();
             sendMessagingNotification();
             status = READY;
-            // wait for notifications to move through the system
-            delay();
         }
 
         @Override
         void tearDown() {
+            mNm.cancelAll();
             deleteChannel();
         }
 
@@ -1034,42 +906,37 @@
 
         @Override
         void test() {
-            MockListener.probeListenerPosted(mContext,
-                    new MockListener.NotificationResultCatcher() {
-                        @Override
-                        public void accept(List<Notification> result) {
-                            if (result == null || result.size() != 1 || result.get(0) == null) {
-                                logFail();
-                                status = FAIL;
-                                next();
-                                return;
-                            }
-                            // Can only read in MessaginStyle using the compat class.
-                            NotificationCompat.MessagingStyle readStyle =
-                                    NotificationCompat.MessagingStyle
-                                        .extractMessagingStyleFromNotification(
-                                              result.get(0));
-                            if (readStyle == null || readStyle.getMessages().size() != 2) {
-                                status = FAIL;
-                                logFail();
-                                next();
-                                return;
-                            }
+            List<Notification> result =
+                    new ArrayList<>(MockListener.getInstance().mPostedNotifications);
+            if (result.size() != 1 || result.get(0) == null) {
+                logFail();
+                status = FAIL;
+                next();
+                return;
+            }
+            // Can only read in MessaginStyle using the compat class.
+            NotificationCompat.MessagingStyle readStyle =
+                    NotificationCompat.MessagingStyle
+                            .extractMessagingStyleFromNotification(
+                                    result.get(0));
+            if (readStyle == null || readStyle.getMessages().size() != 2) {
+                status = FAIL;
+                logFail();
+                next();
+                return;
+            }
 
-                            if (!verifyMessage(readStyle.getMessages().get(0), extrasKey1, extrasValue1)
-                                    || !verifyMessage(
-                                    readStyle.getMessages().get(1), extrasKey2, extrasValue2)) {
-                                status = FAIL;
-                                logFail();
-                                next();
-                                return;
-                            }
+            if (!verifyMessage(readStyle.getMessages().get(0), extrasKey1,
+                    extrasValue1)
+                    || !verifyMessage(
+                    readStyle.getMessages().get(1), extrasKey2, extrasValue2)) {
+                status = FAIL;
+                logFail();
+                next();
+                return;
+            }
 
-                            status = PASS;
-                            next();
-                        }
-                    });
-            delay();  // in case the catcher never returns
+            status = PASS;
         }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
index 0389584..9f6d72b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
@@ -92,13 +92,13 @@
             @Override
             protected Throwable doInBackground(Void... params) {
                 try {
+                    assertEquals("Android CTS", accessory.getManufacturer());
+                    assertEquals("Android CTS test companion device", accessory.getModel());
                     assertEquals("Android device running CTS verifier", accessory.getDescription());
-                    assertEquals("Android", accessory.getManufacturer());
-                    assertEquals("Android device", accessory.getModel());
-                    assertEquals("0", accessory.getSerial());
+                    assertEquals("2", accessory.getVersion());
                     assertEquals("https://source.android.com/compatibility/cts/verifier.html",
                             accessory.getUri());
-                    assertEquals("1", accessory.getVersion());
+                    assertEquals("0", accessory.getSerial());
 
                     assertTrue(Arrays.asList(usbManager.getAccessoryList()).contains(accessory));
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
index 604169a..9dc690b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
@@ -214,12 +214,12 @@
      */
     private void makeThisDeviceAnAccessory(@NonNull UsbDeviceConnection connection) {
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
-                "Android");
+                "Android CTS");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
-                "Android device");
+                "Android device under CTS test");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
                 "Android device running CTS verifier");
-        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "1");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "2");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI,
                 "https://source.android.com/compatibility/cts/verifier.html");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, "0");
diff --git a/apps/CtsVerifierUSBCompanion/res/xml/accessory_filter.xml b/apps/CtsVerifierUSBCompanion/res/xml/accessory_filter.xml
index b511879..13f29c7 100644
--- a/apps/CtsVerifierUSBCompanion/res/xml/accessory_filter.xml
+++ b/apps/CtsVerifierUSBCompanion/res/xml/accessory_filter.xml
@@ -15,5 +15,5 @@
    limitations under the License.
   -->
 <resources>
-    <usb-accessory />
+    <usb-accessory manufacturer="Android CTS" model="Android device under CTS test" version="2" />
 </resources>
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
index 0bf8ca2..ac025d1 100644
--- a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
@@ -341,12 +341,12 @@
      */
     private void makeThisDeviceAnAccessory(@NonNull UsbDeviceConnection connection) {
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
-                "Android");
+                "Android CTS");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
-                "Android device");
+                "Android CTS test companion device");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
                 "Android device running CTS verifier");
-        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "1");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "2");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI,
                 "https://source.android.com/compatibility/cts/verifier.html");
         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, "0");
diff --git a/apps/EmptyDeviceAdmin/Android.mk b/apps/EmptyDeviceAdmin/Android.mk
index 3d76129..1d68fbb 100644
--- a/apps/EmptyDeviceAdmin/Android.mk
+++ b/apps/EmptyDeviceAdmin/Android.mk
@@ -29,6 +29,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/apps/PermissionApp/Android.mk b/apps/PermissionApp/Android.mk
index 4bcc585..f22ecc3 100644
--- a/apps/PermissionApp/Android.mk
+++ b/apps/PermissionApp/Android.mk
@@ -29,6 +29,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/apps/VpnApp/Android.mk
similarity index 71%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to apps/VpnApp/Android.mk
index 151379b..cb223a3 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/apps/VpnApp/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -16,11 +16,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
+# Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/apps/VpnApp/api23/Android.mk
similarity index 75%
copy from hostsidetests/devicepolicy/app/VpnApp/Android.mk
copy to apps/VpnApp/api23/Android.mk
index 9723b97..9f3f2e7 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/apps/VpnApp/api23/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -16,19 +16,19 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsVpnFirewallApp
+LOCAL_PACKAGE_NAME := CtsVpnFirewallAppApi23
 
 LOCAL_MODULE_TAGS := optional
 
 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)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml b/apps/VpnApp/api23/AndroidManifest.xml
similarity index 62%
copy from hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml
copy to apps/VpnApp/api23/AndroidManifest.xml
index ea1a001..b00e1a5 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml
+++ b/apps/VpnApp/api23/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
@@ -15,11 +15,19 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.vpnfirewall">
+        package="com.android.cts.vpnfirewall">
 
-    <uses-sdk android:minSdkVersion="22"/>
+    <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="23"/>
 
-    <application>
+    <application android:label="@string/app">
+        <activity android:name=".VpnClient">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <action android:name="com.android.cts.vpnfirewall.action.CONNECT_AND_FINISH"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
         <service android:name=".ReflectorVpnService"
                 android:permission="android.permission.BIND_VPN_SERVICE">
             <intent-filter>
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/apps/VpnApp/api24/Android.mk
similarity index 75%
copy from hostsidetests/devicepolicy/app/VpnApp/Android.mk
copy to apps/VpnApp/api24/Android.mk
index 9723b97..fc2761c 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/apps/VpnApp/api24/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -16,19 +16,19 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsVpnFirewallApp
+LOCAL_PACKAGE_NAME := CtsVpnFirewallAppApi24
 
 LOCAL_MODULE_TAGS := optional
 
 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)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/apps/VpnApp/api24/AndroidManifest.xml b/apps/VpnApp/api24/AndroidManifest.xml
new file mode 100644
index 0000000..c0c0df6
--- /dev/null
+++ b/apps/VpnApp/api24/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?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="com.android.cts.vpnfirewall">
+
+    <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="24"/>
+
+    <application android:label="@string/app">
+        <activity android:name=".VpnClient">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <action android:name="com.android.cts.vpnfirewall.action.CONNECT_AND_FINISH"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <service android:name=".ReflectorVpnService"
+                android:permission="android.permission.BIND_VPN_SERVICE">
+            <!-- Dummy entry below to test the default value of always-on opt-opt flag -->
+            <meta-data android:name="dummy-name" android:value="dummy-value"/>
+            <intent-filter>
+                <action android:name="android.net.VpnService"/>
+            </intent-filter>
+        </service>
+    </application>
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/apps/VpnApp/latest/Android.mk
similarity index 84%
rename from hostsidetests/devicepolicy/app/VpnApp/Android.mk
rename to apps/VpnApp/latest/Android.mk
index 9723b97..a8db2d2 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/apps/VpnApp/latest/Android.mk
@@ -22,13 +22,13 @@
 
 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)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml b/apps/VpnApp/latest/AndroidManifest.xml
similarity index 70%
rename from hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml
rename to apps/VpnApp/latest/AndroidManifest.xml
index ea1a001..6cc706f 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml
+++ b/apps/VpnApp/latest/AndroidManifest.xml
@@ -15,11 +15,19 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.vpnfirewall">
+        package="com.android.cts.vpnfirewall">
 
     <uses-sdk android:minSdkVersion="22"/>
 
-    <application>
+    <application android:label="@string/app">
+        <activity android:name=".VpnClient">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <action android:name="com.android.cts.vpnfirewall.action.CONNECT_AND_FINISH"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
         <service android:name=".ReflectorVpnService"
                 android:permission="android.permission.BIND_VPN_SERVICE">
             <intent-filter>
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/apps/VpnApp/notalwayson/Android.mk
similarity index 75%
copy from hostsidetests/devicepolicy/app/VpnApp/Android.mk
copy to apps/VpnApp/notalwayson/Android.mk
index 9723b97..cc1bfec 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/apps/VpnApp/notalwayson/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -16,19 +16,19 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsVpnFirewallApp
+LOCAL_PACKAGE_NAME := CtsVpnFirewallAppNotAlwaysOn
 
 LOCAL_MODULE_TAGS := optional
 
 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)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml b/apps/VpnApp/notalwayson/AndroidManifest.xml
similarity index 61%
copy from hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml
copy to apps/VpnApp/notalwayson/AndroidManifest.xml
index ea1a001..fc250aa 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/AndroidManifest.xml
+++ b/apps/VpnApp/notalwayson/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
@@ -15,16 +15,26 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.vpnfirewall">
+        package="com.android.cts.vpnfirewall">
 
     <uses-sdk android:minSdkVersion="22"/>
 
-    <application>
+    <application android:label="@string/app">
+        <activity android:name=".VpnClient">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <action android:name="com.android.cts.vpnfirewall.action.CONNECT_AND_FINISH"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
         <service android:name=".ReflectorVpnService"
                 android:permission="android.permission.BIND_VPN_SERVICE">
             <intent-filter>
                 <action android:name="android.net.VpnService"/>
             </intent-filter>
+            <meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
+                       android:value="false"/>
         </service>
     </application>
 
diff --git a/apps/VpnApp/res/layout/vpn_client.xml b/apps/VpnApp/res/layout/vpn_client.xml
new file mode 100644
index 0000000..a3a14ae
--- /dev/null
+++ b/apps/VpnApp/res/layout/vpn_client.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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+    <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:padding="3mm">
+        <Button style="@style/item" android:id="@+id/connect" android:text="@string/connect"/>
+    </LinearLayout>
+</ScrollView>
diff --git a/apps/VpnApp/res/values/strings.xml b/apps/VpnApp/res/values/strings.xml
new file mode 100644
index 0000000..ec86c71
--- /dev/null
+++ b/apps/VpnApp/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?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>
+    <string name="app">CtsVpnFirewallApp</string>
+    <string name="connect">Connect!</string>
+</resources>
diff --git a/apps/VpnApp/res/values/styles.xml b/apps/VpnApp/res/values/styles.xml
new file mode 100644
index 0000000..6f4011b
--- /dev/null
+++ b/apps/VpnApp/res/values/styles.xml
@@ -0,0 +1,25 @@
+<?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="item">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:singleLine">true</item>
+    </style>
+</resources>
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/IcmpMessage.java b/apps/VpnApp/src/com/android/cts/vpnfirewall/IcmpMessage.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/IcmpMessage.java
rename to apps/VpnApp/src/com/android/cts/vpnfirewall/IcmpMessage.java
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/Ipv4Packet.java b/apps/VpnApp/src/com/android/cts/vpnfirewall/Ipv4Packet.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/Ipv4Packet.java
rename to apps/VpnApp/src/com/android/cts/vpnfirewall/Ipv4Packet.java
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/PingReflector.java b/apps/VpnApp/src/com/android/cts/vpnfirewall/PingReflector.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/PingReflector.java
rename to apps/VpnApp/src/com/android/cts/vpnfirewall/PingReflector.java
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java b/apps/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
rename to apps/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/Rfc1071.java b/apps/VpnApp/src/com/android/cts/vpnfirewall/Rfc1071.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/Rfc1071.java
rename to apps/VpnApp/src/com/android/cts/vpnfirewall/Rfc1071.java
diff --git a/apps/VpnApp/src/com/android/cts/vpnfirewall/VpnClient.java b/apps/VpnApp/src/com/android/cts/vpnfirewall/VpnClient.java
new file mode 100644
index 0000000..e4577a5
--- /dev/null
+++ b/apps/VpnApp/src/com/android/cts/vpnfirewall/VpnClient.java
@@ -0,0 +1,61 @@
+/*
+ * 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.cts.vpnfirewall;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.VpnService;
+import android.os.Bundle;
+
+public class VpnClient extends Activity {
+
+    public static final String ACTION_CONNECT_AND_FINISH =
+            "com.android.cts.vpnfirewall.action.CONNECT_AND_FINISH";
+
+    private static final int REQUEST_CONNECT = 0;
+    private static final int REQUEST_CONNECT_AND_FINISH = 1;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.vpn_client);
+
+        if (ACTION_CONNECT_AND_FINISH.equals(getIntent().getAction())) {
+            prepareAndStart(REQUEST_CONNECT_AND_FINISH);
+        }
+        findViewById(R.id.connect).setOnClickListener(v -> prepareAndStart(REQUEST_CONNECT));
+    }
+
+    @Override
+    protected void onActivityResult(int request, int result, Intent data) {
+        if (result == RESULT_OK) {
+            startService(new Intent(this, ReflectorVpnService.class));
+        }
+        if (request == REQUEST_CONNECT_AND_FINISH) {
+            finish();
+        }
+    }
+
+    private void prepareAndStart(int requestCode) {
+        Intent intent = VpnService.prepare(VpnClient.this);
+        if (intent != null) {
+            startActivityForResult(intent, requestCode);
+        } else {
+            onActivityResult(requestCode, RESULT_OK, null);
+        }
+    }
+}
diff --git a/build/device_info_package.mk b/build/device_info_package.mk
index dcc81d3..d9d08e8 100644
--- a/build/device_info_package.mk
+++ b/build/device_info_package.mk
@@ -49,7 +49,7 @@
 
 # Generator of APK manifests.
 MANIFEST_GENERATOR_JAR := $(HOST_OUT_JAVA_LIBRARIES)/compatibility-manifest-generator.jar
-MANIFEST_GENERATOR := java -jar $(MANIFEST_GENERATOR_JAR)
+MANIFEST_GENERATOR := $(JAVA) -jar $(MANIFEST_GENERATOR_JAR)
 
 # Generate the manifest
 manifest_xml := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/AndroidManifest.xml
diff --git a/common/device-side/util/jni/Android.mk b/common/device-side/util/jni/Android.mk
index 7b73707..8627d24 100644
--- a/common/device-side/util/jni/Android.mk
+++ b/common/device-side/util/jni/Android.mk
@@ -32,4 +32,6 @@
 LOCAL_STATIC_LIBRARIES := cpufeatures
 LOCAL_SDK_VERSION := 19
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
index 1727a3a..c7d2fa5 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
@@ -245,6 +245,18 @@
         return getCodecNames(true /* isEncoder */, null /* isGoog */, formats);
     }
 
+    public static String[] getDecoderNamesForMime(String mime) {
+        MediaFormat format = new MediaFormat();
+        format.setString(MediaFormat.KEY_MIME, mime);
+        return getCodecNames(false /* isEncoder */, null /* isGoog */, format);
+    }
+
+    public static String[] getEncoderNamesForMime(String mime) {
+        MediaFormat format = new MediaFormat();
+        format.setString(MediaFormat.KEY_MIME, mime);
+        return getCodecNames(true /* isEncoder */, null /* isGoog */, format);
+    }
+
     public static void verifyNumCodecs(
             int count, boolean isEncoder, Boolean isGoog, MediaFormat... formats) {
         String desc = (isEncoder ? "encoders" : "decoders") + " for "
diff --git a/common/host-side/tradefed/res/report/compatibility_result.css b/common/host-side/tradefed/res/report/compatibility_result.css
index 03032ed..991055a 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.css
+++ b/common/host-side/tradefed/res/report/compatibility_result.css
@@ -14,170 +14,159 @@
 */
 
 body {
-    font-family:arial,sans-serif;
-    color:#000;
-    font-size:13px;
-    color:#333;
-    padding:10;
-    margin:10;
+  color: #333;
+  font-family: arial,sans-serif;
+  font-size: 13px;
+  margin: 10;
+  padding: 10;
 }
 
 /* Report logo and device name */
 table.title {
-    padding:5px;
-    border-width: 0px;
-    margin-left:auto;
-    margin-right:auto;
-    vertical-align:middle;
+  border-width: 0;
+  margin-left: auto;
+  margin-right: auto;
+  padding: 5px;
+  vertical-align: middle;
 }
 
 table.summary {
-    background-color: rgb(212, 233, 169);
-    border-collapse:collapse;
-    border: 0px solid #A5C639;
-    margin-left:auto;
-    margin-right:auto;
+  background-color: #d4e9a9;
+  border: 0 solid #a5c639;
+  border-collapse: collapse;
+  margin-left: auto;
+  margin-right: auto;
 }
 
 table.summary th {
-    background-color: #A5C639;
-    font-size: 1.2em;
-    padding: 0.5em;
+  background-color: #a5c639;
+  font-size: 1.2em;
+  padding: .5em;
 }
 
 table.summary td {
-    border-width: 0px 0px 0px 0px;
-    border-color: gray;
-    border-style: inset;
-    font-size: 1em;
-    padding: 0.5em;
-    vertical-align: top;
+  border: 0 inset #808080;
+  font-size: 1em;
+  padding: .5em;
+  vertical-align: top;
 }
 
 table.testsummary {
-    background-color: rgb(212, 233, 169);
-    border-collapse:collapse;
-    margin-left:auto;
-    margin-right:auto;
+  background-color: #d4e9a9;
+  border-collapse: collapse;
+  margin-left: auto;
+  margin-right: auto;
 }
 
 table.testsummary th {
-    background-color: #A5C639;
-    border: 1px outset gray;
-    padding: 0.5em;
+  background-color: #a5c639;
+  border: 1px outset #808080;
+  padding: .5em;
 }
 
 table.testsummary td {
-    border: 1px outset #A5C639;
-    padding: 0.5em;
-    text-align: center;
+  border: 1px outset #a5c639;
+  padding: .5em;
+  text-align: center;
 }
 
 table.testdetails {
-    background-color: rgb(212, 233, 169);
-    border-collapse:collapse;
-    border-width:1;
-    border-color: #A5C639;
-    margin-left:auto;
-    margin-right:auto;
-    margin-bottom: 2em;
-    vertical-align: top;
-    width: 95%;
+  background-color: #d4e9a9;
+  border-collapse: collapse;
+  border-color: #a5c639;
+  border-width: 1;
+  margin-bottom: 2em;
+  margin-left: auto;
+  margin-right: auto;
+  vertical-align: top;
+  width: 95%;
 }
 
 table.testdetails th {
-    background-color: #A5C639;
-    border-width: 1px;
-    border-color: gray;
-    border-style: outset;
-    height: 2em;
-    padding: 0.2em;
+  background-color: #a5c639;
+  border: 1px outset #808080;
+  height: 2em;
+  padding: .2em;
 }
 
 table.testdetails td {
-    border-width: 1px;
-    border-color: #A5C639;
-    border-style: outset;
-    text-align: left;
-    vertical-align: top;
-    padding: 0.2em;
+  border: 1px outset #a5c639;
+  padding: .2em;
+  text-align: left;
+  vertical-align: top;
 }
 
 table.testdetails td.module {
-    background-color: white;
-    border: 0px;
-    font-weight: bold;
+  background-color: #fff;
+  border: 0;
+  font-weight: bold;
 }
 
 table.incompletemodules {
-    background-color: rgb(212, 233, 169);
-    border-collapse:collapse;
-    margin-left:auto;
-    margin-right:auto;
+  background-color: #d4e9a9;
+  border-collapse: collapse;
+  margin-left: auto;
+  margin-right: auto;
 }
 
 table.incompletemodules th {
-    background-color: #A5C639;
-    border: 1px outset gray;
-    padding: 0.5em;
+  background-color: #a5c639;
+  border: 1px outset #808080;
+  padding: .5em;
 }
 
 table.incompletemodules td {
-    border: 1px outset #A5C639;
-    padding: 0.5em;
-    text-align: center;
+  border: 1px outset #a5c639;
+  padding: .5em;
+  text-align: center;
 }
 
 /* Test cell details */
 td.failed {
-    background-color: #FA5858;
-    font-weight:bold;
-    vertical-align: top;
-    text-align: center;
+  background-color: #fa5858;
+  font-weight: bold;
+  text-align: center;
+  vertical-align: top;
 }
 
 td.failuredetails {
-    text-align: left;
+  text-align: left;
 }
 
 td.pass {
-    text-align: center;
-    margin-left:auto;
-    margin-right:auto;
+  margin-left: auto;
+  margin-right: auto;
+  text-align: center;
 }
 
 td.not_executed {
-    background-color: #A5C639;
-    vertical-align: top;
-    text-align: center;
+  background-color: #a5c639;
+  text-align: center;
+  vertical-align: top;
 }
 
 td.testname {
-    border-width: 1px;
-    border-color: #A5C639;
-    border-style: outset;
-    text-align: left;
-    vertical-align: top;
-    padding:1;
-    overflow:hidden;
+  border: 1px outset #a5c639;
+  overflow: hidden;
+  padding: 1;
+  text-align: left;
+  vertical-align: top;
 }
 
 td.testcase {
-    border-width: 1px;
-    border-color: #A5C639;
-    border-style: outset;
-    text-align: left;
-    vertical-align: top;
-    padding:1;
-    overflow:hidden;
-    font-weight:bold;
+  border: 1px outset #a5c639;
+  font-weight: bold;
+  overflow: hidden;
+  padding: 1;
+  text-align: left;
+  vertical-align: top;
 }
 
 div.details {
-    white-space: pre-wrap;       /* css-3 */
-    white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
-    white-space: -pre-wrap;      /* Opera 4-6 */
-    white-space: -o-pre-wrap;    /* Opera 7 */
-    word-wrap: break-word;       /* Internet Explorer 5.5+ */
-    overflow:auto;
+  overflow: auto;
+  white-space: pre-wrap;       /* css-3 */
+  white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
+  white-space: -pre-wrap;      /* Opera 4-6 */
+  white-space: -o-pre-wrap;    /* Opera 7 */
+  word-wrap: break-word;       /* Internet Explorer 5.5+ */
 }
diff --git a/error_prone_rules.mk b/error_prone_rules.mk
index cc28b0d..25d9344 100644
--- a/error_prone_rules.mk
+++ b/error_prone_rules.mk
@@ -16,8 +16,10 @@
 LOCAL_ERROR_PRONE_FLAGS:= -Xep:ArrayToString:ERROR \
                           -Xep:BoxedPrimitiveConstructor:ERROR \
                           -Xep:ConstantField:ERROR \
+                          -Xep:EqualsIncompatibleType:ERROR \
                           -Xep:FormatString:ERROR \
                           -Xep:GetClassOnClass:ERROR \
+                          -Xep:IdentityBinaryExpression:ERROR \
                           -Xep:JUnit3TestNotRun:ERROR \
                           -Xep:JUnitAmbiguousTestClass:ERROR \
                           -Xep:MissingFail:ERROR \
diff --git a/error_prone_rules_tests.mk b/error_prone_rules_tests.mk
index 1effdba..d17828d6 100644
--- a/error_prone_rules_tests.mk
+++ b/error_prone_rules_tests.mk
@@ -15,9 +15,11 @@
 # Set of error prone rules to ensure code quality of tests
 
 # Goal is to eventually merge with error_prone_rules.mk
-LOCAL_ERROR_PRONE_FLAGS:= -Xep:CollectionIncompatibleType:ERROR \
+LOCAL_ERROR_PRONE_FLAGS:= -Xep:ArrayToString:ERROR \
+                          -Xep:CollectionIncompatibleType:ERROR \
                           -Xep:EqualsNaN:ERROR \
                           -Xep:FormatString:ERROR \
                           -Xep:JUnit3TestNotRun:ERROR \
+                          -Xep:SizeGreaterThanOrEqualsZero:ERROR \
                           -Xep:TryFailThrowable:ERROR
 
diff --git a/hostsidetests/aadb/Android.mk b/hostsidetests/aadb/Android.mk
index 203151b..5f0a967 100644
--- a/hostsidetests/aadb/Android.mk
+++ b/hostsidetests/aadb/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.aadb
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/abioverride/Android.mk b/hostsidetests/abioverride/Android.mk
index 9b92985..0877b43 100644
--- a/hostsidetests/abioverride/Android.mk
+++ b/hostsidetests/abioverride/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CTS_TEST_PACKAGE := android.host.abioverride
 
diff --git a/hostsidetests/abioverride/app/Android.mk b/hostsidetests/abioverride/app/Android.mk
index e49622c..a246f72 100755
--- a/hostsidetests/abioverride/app/Android.mk
+++ b/hostsidetests/abioverride/app/Android.mk
@@ -34,7 +34,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAbiOverrideTestApp
 
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index fa78eab..975bcb5 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.appsecurity
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index afd7245..ec10304 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -41,6 +41,8 @@
     private IAbi mAbi;
     private IBuildInfo mCtsBuild;
 
+    private int[] mUsers;
+
     @Override
     public void setAbi(IAbi abi) {
         mAbi = abi;
@@ -55,11 +57,12 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        Utils.prepareSingleUser(getDevice());
+        mUsers = Utils.prepareMultipleUsers(getDevice(), Integer.MAX_VALUE);
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
 
         getDevice().uninstallPackage(PKG);
+        getDevice().executeShellCommand("sm set-virtual-disk true");
     }
 
     @Override
@@ -67,10 +70,10 @@
         super.tearDown();
 
         getDevice().uninstallPackage(PKG);
+        getDevice().executeShellCommand("sm set-virtual-disk false");
     }
 
     public void testApps() throws Exception {
-        if (!hasAdoptable()) return;
         final String diskId = getAdoptionDisk();
         try {
             final String abi = mAbi.getName();
@@ -79,10 +82,12 @@
 
             // Install simple app on internal
             new InstallMultiple().useNaturalAbi().addApk(APK).addApk(apk).run();
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            runDeviceTests(PKG, CLASS, "testDataWrite");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataInternal", user);
+                runDeviceTests(PKG, CLASS, "testDataWrite", user);
+                runDeviceTests(PKG, CLASS, "testDataRead", user);
+                runDeviceTests(PKG, CLASS, "testNative", user);
+            }
 
             // Adopt that disk!
             assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
@@ -91,28 +96,36 @@
             // Move app and verify
             assertSuccess(getDevice().executeShellCommand(
                     "pm move-package " + PKG + " " + vol.uuid));
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataNotInternal", user);
+                runDeviceTests(PKG, CLASS, "testDataRead", user);
+                runDeviceTests(PKG, CLASS, "testNative", user);
+            }
 
             // Unmount, remount and verify
-            getDevice().executeShellCommand("sm unmount " + vol.volId);
-            getDevice().executeShellCommand("sm mount " + vol.volId);
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
+            unmount(vol);
+            mount(vol);
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataNotInternal", user);
+                runDeviceTests(PKG, CLASS, "testDataRead", user);
+                runDeviceTests(PKG, CLASS, "testNative", user);
+            }
 
             // Move app back and verify
             assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " internal"));
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataInternal", user);
+                runDeviceTests(PKG, CLASS, "testDataRead", user);
+                runDeviceTests(PKG, CLASS, "testNative", user);
+            }
 
             // Un-adopt volume and app should still be fine
             getDevice().executeShellCommand("sm partition " + diskId + " public");
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataInternal", user);
+                runDeviceTests(PKG, CLASS, "testDataRead", user);
+                runDeviceTests(PKG, CLASS, "testNative", user);
+            }
 
         } finally {
             cleanUp(diskId);
@@ -120,7 +133,6 @@
     }
 
     public void testPrimaryStorage() throws Exception {
-        if (!hasAdoptable()) return;
         final String diskId = getAdoptionDisk();
         try {
             final String originalVol = getDevice()
@@ -139,10 +151,12 @@
     private void verifyPrimaryInternal(String diskId) throws Exception {
         // Write some data to shared storage
         new InstallMultiple().addApk(APK).run();
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryInternal", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataWrite", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         // Adopt that disk!
         assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
@@ -153,20 +167,28 @@
         getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid, out, 2,
                 TimeUnit.HOURS, 1);
         assertSuccess(out.getOutput());
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryAdopted", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         // Unmount and verify
-        getDevice().executeShellCommand("sm unmount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
-        getDevice().executeShellCommand("sm mount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        unmount(vol);
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryUnmounted", user);
+        }
+        mount(vol);
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryAdopted", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         // Move app and verify backing storage volume is same
         assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " " + vol.uuid));
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         // And move back to internal
         out = new CollectingOutputReceiver();
@@ -174,20 +196,26 @@
                 TimeUnit.HOURS, 1);
         assertSuccess(out.getOutput());
 
-        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryInternal", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " internal"));
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
     }
 
     private void verifyPrimaryPhysical(String diskId) throws Exception {
         // Write some data to shared storage
         new InstallMultiple().addApk(APK).run();
-        runDeviceTests(PKG, CLASS, "testPrimaryPhysical");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryPhysical", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataWrite", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         // Adopt that disk!
         assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
@@ -196,22 +224,30 @@
         // Move primary storage there, but since we just nuked primary physical
         // the storage device will be empty
         assertSuccess(getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid));
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryAdopted", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataWrite", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         // Unmount and verify
-        getDevice().executeShellCommand("sm unmount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
-        getDevice().executeShellCommand("sm mount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        unmount(vol);
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryUnmounted", user);
+        }
+        mount(vol);
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryAdopted", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
 
         // And move to internal
         assertSuccess(getDevice().executeShellCommand("pm move-primary-storage internal"));
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+        for (int user : mUsers) {
+            runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryInternal", user);
+            runDeviceTests(PKG, CLASS, "testPrimaryDataRead", user);
+        }
     }
 
     /**
@@ -219,7 +255,6 @@
      * adopted volumes.
      */
     public void testPackageInstaller() throws Exception {
-        if (!hasAdoptable()) return;
         final String diskId = getAdoptionDisk();
         try {
             assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
@@ -228,14 +263,18 @@
             // Install directly onto adopted volume
             new InstallMultiple().locationAuto().forceUuid(vol.uuid)
                     .addApk(APK).addApk(APK_mdpi).run();
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDensityBest1");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataNotInternal", user);
+                runDeviceTests(PKG, CLASS, "testDensityBest1", user);
+            }
 
             // Now splice in an additional split which offers better resources
             new InstallMultiple().locationAuto().inheritFrom(PKG)
                     .addApk(APK_xxhdpi).run();
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDensityBest2");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataNotInternal", user);
+                runDeviceTests(PKG, CLASS, "testDensityBest2", user);
+            }
 
         } finally {
             cleanUp(diskId);
@@ -247,7 +286,6 @@
      * returned at a later time.
      */
     public void testEjected() throws Exception {
-        if (!hasAdoptable()) return;
         final String diskId = getAdoptionDisk();
         try {
             assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
@@ -255,35 +293,43 @@
 
             // Install directly onto adopted volume, and write data there
             new InstallMultiple().locationAuto().forceUuid(vol.uuid).addApk(APK).run();
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDataWrite");
-            runDeviceTests(PKG, CLASS, "testDataRead");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataNotInternal", user);
+                runDeviceTests(PKG, CLASS, "testDataWrite", user);
+                runDeviceTests(PKG, CLASS, "testDataRead", user);
+            }
 
             // Now unmount and uninstall; leaving stale package on adopted volume
-            getDevice().executeShellCommand("sm unmount " + vol.volId);
+            unmount(vol);
             getDevice().uninstallPackage(PKG);
 
             // Install second copy on internal, but don't write anything
             new InstallMultiple().locationInternalOnly().addApk(APK).run();
-            runDeviceTests(PKG, CLASS, "testDataInternal");
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataInternal", user);
+            }
 
             // Kick through a remount cycle, which should purge the adopted app
-            getDevice().executeShellCommand("sm mount " + vol.volId);
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            boolean didThrow = false;
-            try {
-                runDeviceTests(PKG, CLASS, "testDataRead");
-            } catch (AssertionError expected) {
-                didThrow = true;
+            mount(vol);
+            for (int user : mUsers) {
+                runDeviceTests(PKG, CLASS, "testDataInternal", user);
             }
-            if (!didThrow) {
-                fail("Unexpected data from adopted volume picked up");
+            for (int user : mUsers) {
+                boolean threw = false;
+                try {
+                    runDeviceTests(PKG, CLASS, "testDataRead", user);
+                } catch (AssertionError expected) {
+                    threw = true;
+                }
+                if (!threw) {
+                    fail("Unexpected data from adopted volume picked up from user " + user);
+                }
             }
-            getDevice().executeShellCommand("sm unmount " + vol.volId);
+            unmount(vol);
 
             // Uninstall the internal copy and remount; we should have no record of app
             getDevice().uninstallPackage(PKG);
-            getDevice().executeShellCommand("sm mount " + vol.volId);
+            mount(vol);
 
             assertEmpty(getDevice().executeShellCommand("pm list packages " + PKG));
         } finally {
@@ -291,10 +337,6 @@
         }
     }
 
-    private boolean hasAdoptable() throws Exception {
-        return Boolean.parseBoolean(getDevice().executeShellCommand("sm has-adoptable").trim());
-    }
-
     private String getAdoptionDisk() throws Exception {
         // In the case where we run multiple test we cleanup the state of the device. This
         // results in the execution of sm forget all which causes the MountService to "reset"
@@ -330,14 +372,38 @@
         throw new AssertionError("Expected private volume; found " + Arrays.toString(lines));
     }
 
+    private void unmount(LocalVolumeInfo vol) throws Exception {
+        getDevice().executeShellCommand("sm unmount " + vol.volId);
+        for (int i = 0; i < 15; i++) {
+            final String raw = getDevice().executeShellCommand("dumpsys package volumes");
+            if (raw.contains("Loaded volumes:") && !raw.contains(vol.volId)) {
+                return;
+            }
+            Thread.sleep(1000);
+        }
+        throw new AssertionError("Private volume " + vol.volId + " failed to be unloaded");
+    }
+
+    private void mount(LocalVolumeInfo vol) throws Exception {
+        getDevice().executeShellCommand("sm mount " + vol.volId);
+        for (int i = 0; i < 15; i++) {
+            final String raw = getDevice().executeShellCommand("dumpsys package volumes");
+            if (raw.contains("Loaded volumes:") && raw.contains(vol.volId)) {
+                return;
+            }
+            Thread.sleep(1000);
+        }
+        throw new AssertionError("Private volume " + vol.volId + " failed to be loaded");
+    }
+
     private void cleanUp(String diskId) throws Exception {
         getDevice().executeShellCommand("sm partition " + diskId + " public");
         getDevice().executeShellCommand("sm forget all");
     }
 
-    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
-            throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+    private void runDeviceTests(String packageName, String testClassName, String testMethodName,
+            int userId) throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName, userId);
     }
 
     private static void assertSuccess(String str) {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
new file mode 100644
index 0000000..e291771
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.appsecurity.cts;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+public class ClassloaderSplitsTest extends DeviceTestCase implements IBuildReceiver {
+    private static final String PKG = "com.android.cts.classloadersplitapp";
+    private static final String TEST_CLASS = PKG + ".SplitAppTest";
+
+    /* The feature hierarchy looks like this:
+
+        APK_BASE (PathClassLoader)
+          ^
+          |
+        APK_FEATURE_A (DelegateLastClassLoader)
+          ^
+          |
+        APK_FEATURE_B (PathClassLoader)
+
+     */
+
+    private static final String APK_BASE = "CtsClassloaderSplitApp.apk";
+    private static final String APK_FEATURE_A = "CtsClassloaderSplitAppFeatureA.apk";
+    private static final String APK_FEATURE_B = "CtsClassloaderSplitAppFeatureB.apk";
+
+    private IBuildInfo mBuildInfo;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        Utils.prepareSingleUser(getDevice());
+        getDevice().uninstallPackage(PKG);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        getDevice().uninstallPackage(PKG);
+    }
+
+    public void testBaseClassLoader() throws Exception {
+        new InstallMultiple().addApk(APK_BASE).run();
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testBaseClassLoader");
+    }
+
+    public void testFeatureAClassLoader() throws Exception {
+        new InstallMultiple().addApk(APK_BASE).addApk(APK_FEATURE_A).run();
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testBaseClassLoader");
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testFeatureAClassLoader");
+    }
+
+    public void testFeatureBClassLoader() throws Exception {
+        new InstallMultiple().addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B).run();
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testBaseClassLoader");
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testFeatureAClassLoader");
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testFeatureBClassLoader");
+    }
+
+    public void testReceiverClassLoaders() throws Exception {
+        new InstallMultiple().addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B).run();
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testBaseClassLoader");
+        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "testAllReceivers");
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuildInfo = buildInfo;
+    }
+
+    private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            super(getDevice(), mBuildInfo, null);
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index cc42e9a..54ac8fa 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -34,7 +34,9 @@
 
     private static final String APK_22 = "CtsUsePermissionApp22.apk";
     private static final String APK_23 = "CtsUsePermissionApp23.apk";
-    private static final String APK_24 = "CtsUsePermissionApp24.apk";
+    private static final String APK_25 = "CtsUsePermissionApp25.apk";
+    private static final String APK_26 = "CtsUsePermissionApp26.apk";
+    private static final String APK_Latest = "CtsUsePermissionAppLatest.apk";
 
     private static final String APK_DECLARE_NON_RUNTIME_PERMISSIONS =
             "CtsDeclareNonRuntimePermissions.apk";
@@ -162,6 +164,24 @@
                 "testRuntimeGroupGrantExpansion");
     }
 
+    public void testRuntimeGroupGrantExpansion25() throws Exception {
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_25), false, false));
+        runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest23",
+                "testRuntimeGroupGrantExpansion");
+    }
+
+    public void testRuntimeGroupGrantExpansion26() throws Exception {
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_26), false, false));
+        runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest26",
+                "testRuntimeGroupGrantNoExpansion");
+    }
+
+    public void testRuntimeGroupGrantExpansionLatest() throws Exception {
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_Latest), false, false));
+        runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest26",
+                "testRuntimeGroupGrantNoExpansion");
+    }
+
     public void testCancelledPermissionRequest23() throws Exception {
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest23",
@@ -230,12 +250,6 @@
                 "testRequestPermissionFromTwoGroups");
     }
 
-//    public void testOnlyRequestedPermissionsGranted24() throws Exception {
-//        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_24), false, false));
-//        runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest24",
-//                "testOnlyRequestedPermissionsGranted");
-//    }
-
     public void testUpgradeKeepsPermissions() throws Exception {
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22",
diff --git a/hostsidetests/appsecurity/test-apps/Android.mk b/hostsidetests/appsecurity/test-apps/Android.mk
index 446e047a..f697a59 100644
--- a/hostsidetests/appsecurity/test-apps/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
index 4faf112..2e6911d 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsAppAccessData
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # although not strictly necessary, sign this app with different cert than CtsAppWithData
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
index c4f0eba..3d11a83 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsAppWithData
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
similarity index 63%
copy from hostsidetests/jvmti/run-tests/test-981/app/Android.mk
copy to hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
index 88727c2..378c53b 100644
--- a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
@@ -1,3 +1,4 @@
+#
 # Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,23 +12,25 @@
 # 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)
+LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
-LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
-LOCAL_MULTILIB := both
 LOCAL_SDK_VERSION := current
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_EXPORT_PACKAGE_RESOURCES := true
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
-# TODO: Refactor. This is the only thing every changing.
-LOCAL_PACKAGE_NAME := CtsJvmtiRunTest981DeviceApp
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-include $(BUILD_PACKAGE)
+LOCAL_PACKAGE_NAME := CtsClassloaderSplitApp
+
+# Tag this module as a cts test artifact
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml
new file mode 100644
index 0000000..05f4573
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?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="com.android.cts.classloadersplitapp"
+    android:isolatedSplits="true">
+
+    <application android:label="ClassloaderSplitApp"
+                 android:classLoader="dalvik.system.PathClassLoader">
+
+        <activity android:name=".BaseActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+          </activity>
+          <receiver android:name=".BaseReceiver">
+            <intent-filter>
+                <action android:name="com.android.cts.classloadersplitapp.ACTION" />
+            </intent-filter>
+          </receiver>
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.cts.classloadersplitapp" />
+
+</manifest>
diff --git a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
similarity index 63%
copy from hostsidetests/jvmti/run-tests/test-981/app/Android.mk
copy to hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
index 88727c2..9016903 100644
--- a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
@@ -1,3 +1,4 @@
+#
 # Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,23 +12,23 @@
 # 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_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SRC_FILES :=
 LOCAL_COMPATIBILITY_SUITE := cts general-tests
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
-LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
-LOCAL_MULTILIB := both
-LOCAL_SDK_VERSION := current
+LOCAL_EXPORT_PACKAGE_RESOURCES := true
+LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureA
 
-# TODO: Refactor. This is the only thing every changing.
-LOCAL_PACKAGE_NAME := CtsJvmtiRunTest981DeviceApp
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-include $(BUILD_PACKAGE)
+LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp
+LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
+
+LOCAL_AAPT_FLAGS += --custom-package com.android.cts.classloadersplitapp.feature_a
+LOCAL_AAPT_FLAGS += --package-id 0x80
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml
new file mode 100644
index 0000000..a334acf
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?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="com.android.cts.classloadersplitapp"
+        featureSplit="feature_a">
+
+    <application android:classLoader="dalvik.system.DelegateLastClassLoader">
+        <activity android:name=".feature_a.FeatureAActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <receiver android:name=".feature_a.FeatureAReceiver">
+            <intent-filter>
+                <action android:name="com.android.cts.classloadersplitapp.ACTION" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
new file mode 100644
index 0000000..ebb2faf
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
@@ -0,0 +1,21 @@
+/*
+ * 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.cts.classloadersplitapp.feature_a;
+
+import com.android.cts.classloadersplitapp.BaseActivity;
+
+public class FeatureAActivity extends BaseActivity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
new file mode 100644
index 0000000..e27a280
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
@@ -0,0 +1,37 @@
+/*
+ * 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.cts.classloadersplitapp.feature_a;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.cts.classloadersplitapp.BaseReceiver;
+
+public class FeatureAReceiver extends BaseReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Bundle b = getResultExtras(true);
+
+        // Figure out the classloader that loaded this class and also
+        // its parent loader.
+        final ClassLoader loader = getClass().getClassLoader();
+        final ClassLoader parent = loader.getParent();
+
+        b.putString("featureA_loaderClassName", loader.getClass().getName());
+        b.putString("featureA_parentClassName", parent.getClass().getName());
+    }
+}
diff --git a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
similarity index 63%
copy from hostsidetests/jvmti/run-tests/test-981/app/Android.mk
copy to hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
index 88727c2..89bedb0 100644
--- a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
@@ -1,3 +1,4 @@
+#
 # Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,23 +12,22 @@
 # 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_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SRC_FILES :=
 LOCAL_COMPATIBILITY_SUITE := cts general-tests
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
-LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
-LOCAL_MULTILIB := both
-LOCAL_SDK_VERSION := current
+LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureB
 
-# TODO: Refactor. This is the only thing every changing.
-LOCAL_PACKAGE_NAME := CtsJvmtiRunTest981DeviceApp
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-include $(BUILD_PACKAGE)
+LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp CtsClassloaderSplitAppFeatureA
+LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
+
+LOCAL_AAPT_FLAGS := --custom-package com.android.cts.classloadersplitapp.feature_b
+LOCAL_AAPT_FLAGS += --package-id 0x81
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml
new file mode 100644
index 0000000..8d9ac52
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.classloadersplitapp"
+        featureSplit="feature_b">
+
+    <uses-split android:name="feature_a" />
+
+    <application>
+        <activity android:name=".feature_b.FeatureBActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <receiver android:name=".feature_b.FeatureBReceiver">
+            <intent-filter>
+                <action android:name="com.android.cts.classloadersplitapp.ACTION" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml
similarity index 84%
rename from tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
rename to hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml
index 173435b..fc46307 100644
--- a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 
-<paths xmlns:android="http://schemas.android.com/apk/res/android">
-    <files-path name="apk" path="/" />
-</paths>
\ No newline at end of file
+<resources>
+    <string name="feature_b_string">Feature B String Polish</string>
+</resources>
diff --git a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml
similarity index 84%
copy from tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
copy to hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml
index 173435b..421ce55 100644
--- a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 
-<paths xmlns:android="http://schemas.android.com/apk/res/android">
-    <files-path name="apk" path="/" />
-</paths>
\ No newline at end of file
+<resources>
+    <string name="feature_b_string">Feature B String Default</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
new file mode 100644
index 0000000..86f5015
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
@@ -0,0 +1,21 @@
+/*
+ * 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.cts.classloadersplitapp.feature_b;
+
+import com.android.cts.classloadersplitapp.feature_a.FeatureAActivity;
+
+public class FeatureBActivity extends FeatureAActivity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
new file mode 100644
index 0000000..0a7287d
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
@@ -0,0 +1,37 @@
+/*
+ * 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.cts.classloadersplitapp.feature_b;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.cts.classloadersplitapp.feature_a.FeatureAReceiver;
+
+public class FeatureBReceiver extends FeatureAReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Bundle b = getResultExtras(true);
+
+        // Figure out the classloader that loaded this class and also
+        // its parent loader.
+        final ClassLoader loader = getClass().getClassLoader();
+        final ClassLoader parent = loader.getParent();
+
+        b.putString("featureB_loaderClassName", loader.getClass().getName());
+        b.putString("featureB_parentClassName", parent.getClass().getName());
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java
new file mode 100644
index 0000000..b727d12
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.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 com.android.cts.classloadersplitapp;
+
+import android.app.Activity;
+
+public class BaseActivity extends Activity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java
new file mode 100644
index 0000000..51d883a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java
@@ -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.
+ */
+package com.android.cts.classloadersplitapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class BaseReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Bundle b = getResultExtras(true);
+
+        // Figure out the classloader that loaded this class and also
+        // its parent loader.
+        final ClassLoader loader = getClass().getClassLoader();
+        final ClassLoader parent = loader.getParent();
+
+        b.putString("loaderClassName", loader.getClass().getName());
+        b.putString("parentClassName", parent.getClass().getName());
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java
new file mode 100644
index 0000000..54482a8
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.classloadersplitapp;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+import java.util.Locale;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class SplitAppTest {
+    /* The feature hierarchy looks like this:
+
+        APK_BASE (PathClassLoader)
+          ^
+          |
+        APK_FEATURE_A (DelegateLastClassLoader)
+          ^
+          |
+        APK_FEATURE_B (PathClassLoader)
+
+     */
+
+    private static final String PACKAGE = "com.android.cts.classloadersplitapp";
+    private static final ComponentName FEATURE_A_ACTIVITY =
+            ComponentName.createRelative(PACKAGE, ".feature_a.FeatureAActivity");
+    private static final ComponentName FEATURE_B_ACTIVITY =
+            ComponentName.createRelative(PACKAGE, ".feature_b.FeatureBActivity");
+
+    @Rule
+    public ActivityTestRule<BaseActivity> mBaseActivityRule =
+            new ActivityTestRule<>(BaseActivity.class);
+
+    // Do not launch this activity lazily. We use this rule to launch all feature Activities,
+    // so we use #launchActivity() with the correct Intent.
+    @Rule
+    public ActivityTestRule<Activity> mFeatureActivityRule =
+            new ActivityTestRule<>(Activity.class, true /*initialTouchMode*/,
+                    false /*launchActivity*/);
+
+    @Rule
+    public AppContextTestRule mAppContextTestRule = new AppContextTestRule();
+
+    @Test
+    public void testBaseClassLoader() throws Exception {
+        final Context context = mBaseActivityRule.getActivity();
+        assertEquals("dalvik.system.PathClassLoader",
+            context.getClassLoader().getClass().getName());
+    }
+
+    @Test
+    public void testFeatureAClassLoader() throws Exception {
+        final Context context = mFeatureActivityRule.launchActivity(
+                new Intent().setComponent(FEATURE_A_ACTIVITY));
+
+        // Feature A requests a DelegateLastClassLoader, so make sure
+        // it is given one.
+        final ClassLoader cl = context.getClassLoader();
+        assertEquals("dalvik.system.DelegateLastClassLoader", cl.getClass().getName());
+
+        // Also assert that its parent (the base) is a PathClassLoader.
+        assertEquals("dalvik.system.PathClassLoader", cl.getParent().getClass().getName());
+    }
+
+    @Test
+    public void testFeatureBClassLoader() throws Exception {
+        // Feature B depends on A, so we expect both to be available.
+        final Context context = mFeatureActivityRule.launchActivity(
+                new Intent().setComponent(FEATURE_B_ACTIVITY));
+
+        // Feature B requests a PathClassLoader but it depends on feature A, which
+        // requests a DelegateLastClassLoader.
+        final ClassLoader cl = context.getClassLoader();
+        assertEquals("dalvik.system.PathClassLoader", cl.getClass().getName());
+        assertEquals("dalvik.system.DelegateLastClassLoader", cl.getParent().getClass().getName());
+    }
+
+    @Test
+    public void testAllReceivers() throws Exception {
+        final Context context = mAppContextTestRule.getContext();
+        final ExtrasResultReceiver receiver = sendOrderedBroadcast(context);
+        final Bundle results = receiver.get();
+
+        // Base.
+        assertThat(results.getString("loaderClassName"),
+            equalTo("dalvik.system.PathClassLoader"));
+
+        // Feature A.
+        assertThat(results.getString("featureA_loaderClassName"),
+            equalTo("dalvik.system.DelegateLastClassLoader"));
+        assertThat(results.getString("featureA_parentClassName"),
+            equalTo("dalvik.system.PathClassLoader"));
+
+        // Feature B.
+        assertThat(results.getString("featureB_loaderClassName"),
+            equalTo("dalvik.system.PathClassLoader"));
+        assertThat(results.getString("featureB_parentClassName"),
+            equalTo("dalvik.system.DelegateLastClassLoader"));
+    }
+
+    private static class ExtrasResultReceiver extends BroadcastReceiver {
+        private final CompletableFuture<Bundle> mResult = new CompletableFuture<>();
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mResult.complete(getResultExtras(true));
+        }
+
+        public Bundle get() throws Exception {
+            return mResult.get(5000, TimeUnit.SECONDS);
+        }
+    }
+
+    private static ExtrasResultReceiver sendOrderedBroadcast(Context context) {
+        final ExtrasResultReceiver resultReceiver = new ExtrasResultReceiver();
+        context.sendOrderedBroadcast(new Intent(PACKAGE + ".ACTION").setPackage(PACKAGE), null,
+                resultReceiver, null, 0, null, null);
+        return resultReceiver;
+    }
+
+    private static class AppContextTestRule implements TestRule {
+        private Context mContext;
+
+        @Override
+        public Statement apply(final Statement base, Description description) {
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+                    base.evaluate();
+                }
+            };
+        }
+
+        public Context getContext() {
+            return mContext;
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk
index 1311944..dbf5284 100644
--- a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_PACKAGE_NAME := CtsDeclareNonRuntimePermissions
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_DEX_PREOPT := false
 
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
index 60ece87..0a55834 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsDocumentClient
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
index 0084eb3..7609e33 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsDocumentProvider
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
index a94b206..a4a9436 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsEncryptionApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/Android.mk
index eadbb82..2721a12 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
index 6d0a589..aaeb8c0 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
@@ -27,7 +27,7 @@
 	ctstestrunner
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk
index a7078fe..4f0ee6c 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
index 453dbcb..31a45b0 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
@@ -24,7 +24,7 @@
     legacy-android-test
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk
index e714536..43deb82 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk
@@ -24,7 +24,7 @@
     legacy-android-test
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk
index 930370a..5fa3765 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk
index 24d9f2a..1206e56 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk
@@ -24,7 +24,7 @@
     legacy-android-test
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk
index 5172dff..f446140 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk
@@ -23,7 +23,7 @@
     legacy-android-test
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk
index 4e49387..cd3c04e 100644
--- a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_PACKAGE_NAME := CtsEscalateToRuntimePermissions
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
index 272d0f9..47d468e 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_PACKAGE_NAME := CtsExternalStorageApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_DEX_PREOPT := false
 
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk b/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk
index 5645a7f..56b2586 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_PACKAGE_NAME := CtsInstantCookieApp
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
index d49fe73..a48abbf 100644
--- a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsInstrumentationAppDiffCert
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with different cert than CtsTargetInstrumentationApp
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.mk
index 9225ee2..0834642 100644
--- a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_EXPORT_PACKAGE_RESOURCES := true
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk
index 15a0b25..48b4e3b 100644
--- a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk
@@ -19,7 +19,7 @@
 
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_EXPORT_PACKAGE_RESOURCES := true
 LOCAL_PACKAGE_NAME := CtsIsolatedSplitAppFeatureA
 
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk
index 3b11085..64b5fc3 100644
--- a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk
@@ -19,7 +19,7 @@
 
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_PACKAGE_NAME := CtsIsolatedSplitAppFeatureB
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk
index 70880ba..f21d1d0 100644
--- a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk
@@ -19,7 +19,7 @@
 
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_PACKAGE_NAME := CtsIsolatedSplitAppFeatureC
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
index ff6be32..0744834 100644
--- a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsMultiUserStorageApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_DEX_PREOPT := false
 
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk b/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
index 31b683d..32f36d0 100644
--- a/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_PACKAGE_NAME := CtsNoRestartBase
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
index c92375e..626c0be 100644
--- a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_PACKAGE_NAME := CtsNoRestartFeature
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.mk b/hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.mk
index f1dbf84..dfa703a 100644
--- a/hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsPkgAccessApp
 
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
index 780214b..184b73f 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsPermissionDeclareApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with a different cert than CtsUsePermissionDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
index 78b7f91..a5c227a 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsPermissionDeclareAppCompat
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with a different cert than CtsUsePermissionDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
index 199e429..c941ff2 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 LOCAL_PACKAGE_NAME := CtsPrivilegedUpdateTests
@@ -46,7 +46,7 @@
 LOCAL_BUILT_MODULE_STEM := package.apk
 # Make sure the build system doesn't try to resign the APK
 LOCAL_CERTIFICATE := PRESIGNED
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := CtsShimPrivUpgrade.apk
 
@@ -63,7 +63,7 @@
 LOCAL_BUILT_MODULE_STEM := package.apk
 # Make sure the build system doesn't try to resign the APK
 LOCAL_CERTIFICATE := PRESIGNED
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := CtsShimPrivUpgradeWrongSHA.apk
 
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
index d265b5b..4f828ad 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsReadExternalStorageApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_DEX_PREOPT := false
 
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
index 3437b2f..22464bd 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsSharedUidInstall
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with a different cert than CtsSharedUidInstallDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
index 47b066a..a73d0fc 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsSharedUidInstallDiffCert
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with a different cert than CtsSharedUidInstall
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
index 9309f17..7180a10 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsSimpleAppInstall
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with a different cert than CtsSimpleAppInstallDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
index fe69246..bcd8a4e 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsSimpleAppInstallDiffCert
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with a different cert than CtsSimpleAppInstall
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
index f844a78..9341949 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 v7 fr de
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
 
@@ -56,7 +56,7 @@
 LOCAL_PACKAGE_SPLITS := v7
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MANIFEST_FILE := revision/AndroidManifest.xml
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
@@ -83,7 +83,7 @@
 LOCAL_PACKAGE_SPLITS := v7
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 101 --version-name OneHundredOne --replace-version
@@ -109,7 +109,7 @@
 LOCAL_PACKAGE_SPLITS := v7
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
index 0603cc7..a248b71 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 featureOf := CtsSplitApp
 featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
index e495ad3..fbc7143 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
@@ -24,6 +24,6 @@
 LOCAL_LDLIBS += -llog
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
index fddee79..bad39fb 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
index cddda28..9951098 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
index 9b67d24..f6efcd6 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
index aed7253..aa2de06 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
index 7798a0c..cd4eafc 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
index 8f604d3..2d7d008 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
index cf3dca1..291a3c6 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/StorageAppA/Android.mk b/hostsidetests/appsecurity/test-apps/StorageAppA/Android.mk
index aa75be7..f3d7d35 100644
--- a/hostsidetests/appsecurity/test-apps/StorageAppA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/StorageAppA/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_PACKAGE_NAME := CtsStorageAppA
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/StorageAppB/Android.mk b/hostsidetests/appsecurity/test-apps/StorageAppB/Android.mk
index c335f23..5f85459 100644
--- a/hostsidetests/appsecurity/test-apps/StorageAppB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/StorageAppB/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_PACKAGE_NAME := CtsStorageAppB
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.mk b/hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.mk
index 173deb5..b5c30fb 100644
--- a/hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.mk
@@ -25,7 +25,7 @@
 
 LOCAL_PACKAGE_NAME := CtsStorageStatsApp
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
index c3da07a..fea0878 100644
--- a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsTargetInstrumentationApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with different cert than CtsInstrumentationAppDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
index 8e51f22..2b6c2b0 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
@@ -23,8 +23,9 @@
     android-support-test \
     compatibility-device-util \
     ctstestrunner \
-    ub-uiautomator \
-    legacy-android-test
+    ub-uiautomator
+
+LOCAL_JAVA_LIBRARIES := legacy-android-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java \
@@ -34,7 +35,7 @@
 LOCAL_PACKAGE_NAME := CtsUsePermissionApp22
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
index 5e623d8..305359c 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
@@ -23,8 +23,9 @@
     android-support-test \
     compatibility-device-util \
     ctstestrunner \
-    ub-uiautomator \
-    legacy-android-test
+    ub-uiautomator
+
+LOCAL_JAVA_LIBRARIES := legacy-android-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -32,7 +33,7 @@
 LOCAL_PACKAGE_NAME := CtsUsePermissionApp23
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
index dc528a1..b4ed09f 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
@@ -193,7 +193,6 @@
                 permissions, new boolean[] {true});
 
         // We should now have been granted both of the permissions from this group.
-        // NOTE: This is undesired behavior which will be fixed for target API 24.
         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
                 .checkSelfPermission(Manifest.permission.SEND_SMS));
     }
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/AndroidManifest.xml
deleted file mode 100644
index 64f3f34..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.usepermission">
-
-    <!-- Request two different permissions within the same group -->
-    <uses-permission android:name="android.permission.SEND_SMS" />
-    <uses-permission android:name="android.permission.RECEIVE_SMS" />
-
-    <application>
-        <activity android:name="com.android.cts.usepermission.BasePermissionActivity" />
-    </application>
-
-    <instrumentation
-            android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.usepermission" />
-
-</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/res/values-en-rGB/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/res/values-en-rGB/strings.xml
deleted file mode 100755
index 27c9900..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <string name="Permissions">Permission</string>
-</resources>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/res/values/strings.xml
deleted file mode 100755
index 6675383..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/res/values/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <string name="Permissions">Permissions</string>
-</resources>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/src/com/android/cts/usepermission/UsePermissionTest24.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/src/com/android/cts/usepermission/UsePermissionTest24.java
deleted file mode 100644
index f87c67f..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/src/com/android/cts/usepermission/UsePermissionTest24.java
+++ /dev/null
@@ -1,78 +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.usepermission;
-
-import android.Manifest;
-import android.content.pm.PackageManager;
-import org.junit.Test;
-
-import static junit.framework.Assert.assertEquals;
-
-/**
- * Runtime permission behavior tests for apps targeting API 24
- */
-public class UsePermissionTest24 extends BasePermissionsTest {
-    private static final int REQUEST_CODE_PERMISSIONS = 42;
-
-    @Test
-    public void testOnlyRequestedPermissionsGranted() throws Exception {
-        // Start out without permission
-        assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
-                .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
-        assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
-                .checkSelfPermission(Manifest.permission.SEND_SMS));
-
-        String[] firstPermissions = new String[] {Manifest.permission.RECEIVE_SMS};
-
-        // Request only one permission and confirm
-        BasePermissionActivity.Result firstResult = requestPermissions(firstPermissions,
-                REQUEST_CODE_PERMISSIONS,
-                BasePermissionActivity.class,
-                () -> {
-                    try {
-                        clickAllowButton();
-                        getUiDevice().waitForIdle();
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                });
-
-        // Expect the permission is granted
-        assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
-                firstPermissions, new boolean[] {true});
-
-        // We should not have the other permission in the group
-        assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
-                .checkSelfPermission(Manifest.permission.SEND_SMS));
-
-        String[] secondPermissions = new String[] {Manifest.permission.SEND_SMS};
-
-        // Request the other permission which should be auto-granted
-        BasePermissionActivity.Result secondResult = requestPermissions(secondPermissions,
-                REQUEST_CODE_PERMISSIONS + 1, BasePermissionActivity.class, null);
-
-        // Expect the permission is granted
-        assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
-                secondPermissions, new boolean[] {true});
-
-        // We now should have both permissions
-        assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
-                .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
-        assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
-                .checkSelfPermission(Manifest.permission.SEND_SMS));
-    }
-}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
similarity index 61%
copy from hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
copy to hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
index a71f48b..ac4f272 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
@@ -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.
@@ -19,16 +19,20 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    compatibility-device-util \
+    ctstestrunner \
+    ub-uiautomator
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java \
-    ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+LOCAL_SRC_FILES := $(call all-java-files-under, ../UsePermissionApp23/src) \
+    ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+LOCAL_RESOURCE_DIR := cts/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res
 
-LOCAL_PACKAGE_NAME := CtsUsePermissionApp24
+LOCAL_PACKAGE_NAME := CtsUsePermissionApp25
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/AndroidManifest.xml
new file mode 100644
index 0000000..acaeeb0
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/AndroidManifest.xml
@@ -0,0 +1,77 @@
+<?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="com.android.cts.usepermission">
+
+    <uses-sdk android:minSdkVersion="25" android:targetSdkVersion="25" />
+
+    <!-- Request two different permissions within the same group -->
+    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+    <!-- Contacts -->
+    <!-- Deliberately request WRITE_CONTACTS but *not* READ_CONTACTS -->
+    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+    <!-- Calendar -->
+    <uses-permission android:name="android.permission.READ_CALENDAR"/>
+    <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
+
+    <!-- SMS -->
+    <uses-permission android:name="android.permission.SEND_SMS"/>
+    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+    <uses-permission android:name="android.permission.READ_SMS"/>
+    <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
+    <uses-permission android:name="android.permission.RECEIVE_MMS"/>
+    <uses-permission android:name="android.permission.READ_CELL_BROADCASTS"/>
+
+    <!-- Storage -->
+    <!-- Special case: WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE -->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <!-- Location -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+    <!-- Phone -->
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.CALL_PHONE"/>
+    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+    <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
+    <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"/>
+    <uses-permission android:name="android.permission.USE_SIP"/>
+    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
+
+    <!-- Phone -->
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+    <!-- Camera -->
+    <uses-permission android:name="android.permission.CAMERA"/>
+
+    <!-- Body Sensors -->
+    <uses-permission android:name="android.permission.BODY_SENSORS"/>
+
+    <application>
+        <activity android:name="com.android.cts.usepermission.BasePermissionActivity" />
+    </application>
+
+    <instrumentation
+            android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.cts.usepermission" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
similarity index 74%
rename from hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
rename to hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
index a71f48b..7064288 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
@@ -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.
@@ -19,16 +19,21 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    compatibility-device-util \
+    ctstestrunner \
+    ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java \
     ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+LOCAL_RESOURCE_DIR := cts/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res
 
-LOCAL_PACKAGE_NAME := CtsUsePermissionApp24
+LOCAL_PACKAGE_NAME := CtsUsePermissionApp26
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/AndroidManifest.xml
new file mode 100644
index 0000000..845e43d
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?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="com.android.cts.usepermission">
+    <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26" />
+
+    <!-- Request two different permissions within the same group -->
+    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+    <application>
+        <activity android:name="com.android.cts.usepermission.BasePermissionActivity" />
+    </application>
+
+    <instrumentation
+            android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.cts.usepermission" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/src/com/android/cts/usepermission/UsePermissionTest26.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/src/com/android/cts/usepermission/UsePermissionTest26.java
new file mode 100644
index 0000000..e64838b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/src/com/android/cts/usepermission/UsePermissionTest26.java
@@ -0,0 +1,64 @@
+/*
+ * 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.cts.usepermission;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+
+import org.junit.Test;
+
+/**
+ * Runtime permission behavior tests for apps targeting API 26
+ */
+public class UsePermissionTest26 extends BasePermissionsTest {
+    private static final int REQUEST_CODE_PERMISSIONS = 42;
+
+    @Test
+    public void testRuntimeGroupGrantNoExpansion() throws Exception {
+        // Start out without permission
+        assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+                .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
+        assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+                .checkSelfPermission(Manifest.permission.SEND_SMS));
+
+        String[] permissions = new String[]{Manifest.permission.RECEIVE_SMS};
+
+        // request only one permission from the 'SMS' permission group at runtime,
+        // but two from this group are <uses-permission> in the manifest
+        // request only one permission from the 'contacts' permission group
+        BasePermissionActivity.Result result = requestPermissions(permissions,
+                REQUEST_CODE_PERMISSIONS,
+                BasePermissionActivity.class,
+                () -> {
+                    try {
+                        clickAllowButton();
+                        getUiDevice().waitForIdle();
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                });
+
+        // Expect the permission is granted
+        assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
+                permissions, new boolean[]{true});
+
+        assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getTargetContext()
+                .checkSelfPermission(Manifest.permission.SEND_SMS));
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
similarity index 68%
copy from hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
copy to hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
index a71f48b..62a15e4 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
@@ -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.
@@ -19,16 +19,22 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    compatibility-device-util \
+    ctstestrunner \
+    ub-uiautomator
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+LOCAL_SRC_FILES := $(call all-java-files-under, ../UsePermissionApp26/src)  \
     ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java \
     ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+LOCAL_RESOURCE_DIR := cts/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res
+LOCAL_SDK_VERSION := test_current
 
-LOCAL_PACKAGE_NAME := CtsUsePermissionApp24
+LOCAL_PACKAGE_NAME := CtsUsePermissionAppLatest
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/AndroidManifest.xml
new file mode 100644
index 0000000..cac6790
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/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="com.android.cts.usepermission">
+
+    <!-- Request two different permissions within the same group -->
+    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+    <application>
+        <activity android:name="com.android.cts.usepermission.BasePermissionActivity" />
+    </application>
+
+    <instrumentation
+            android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.cts.usepermission" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
index 80dc334..498e8ca 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsUsePermissionDiffCert
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # sign this app with a different cert than CtsPermissionDeclareApp
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
index 7e5627f..2d67d62 100644
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsUsesLibraryApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
index 9e4e0a2..8574d63 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
@@ -27,7 +27,7 @@
     ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsWriteExternalStorageApp
 
diff --git a/hostsidetests/appsecurity/test-apps/keysets/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/Android.mk
index 5b5fbed..397b49a 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
index 9de77f52..46a6b37 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
index 5b75c49..9018fdb 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
index 41415e9..98a31b9 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
index c4bc3a3..5cf21b4 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -38,6 +38,6 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
index 78b00b3..10c4101 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -40,6 +40,6 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
index 51d8716..907ae36 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
index de64186..d47f6bc 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -36,7 +36,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -49,7 +49,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a
 LOCAL_DEX_PREOPT := false
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -63,6 +63,6 @@
 LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
index d60df9d..87655dd 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
index 54ecb57..764886a 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
index e953f17..d0960c4 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -40,7 +40,7 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -56,6 +56,6 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
index a774832..c6cec13 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -40,6 +40,6 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
index 683d533..e7de019 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
index afb0590..d54a59b 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
@@ -18,7 +18,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
index adfce12..4822a11 100644
--- a/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/hostsidetests/atrace/Android.mk b/hostsidetests/atrace/Android.mk
index 908176c..eb6d14d 100644
--- a/hostsidetests/atrace/Android.mk
+++ b/hostsidetests/atrace/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.host.atrace
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/atrace/AtraceTestApp/Android.mk b/hostsidetests/atrace/AtraceTestApp/Android.mk
index e99d4d1..4b550db 100644
--- a/hostsidetests/atrace/AtraceTestApp/Android.mk
+++ b/hostsidetests/atrace/AtraceTestApp/Android.mk
@@ -31,6 +31,6 @@
 #LOCAL_DEX_PREOPT := false
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/backup/AllowBackup/BackupAllowedApp/Android.mk b/hostsidetests/backup/AllowBackup/BackupAllowedApp/Android.mk
index 6eaf7f0..aa9a22c 100644
--- a/hostsidetests/backup/AllowBackup/BackupAllowedApp/Android.mk
+++ b/hostsidetests/backup/AllowBackup/BackupAllowedApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := BackupAllowedApp
 
diff --git a/hostsidetests/backup/AllowBackup/BackupNotAllowedApp/Android.mk b/hostsidetests/backup/AllowBackup/BackupNotAllowedApp/Android.mk
index e8c70b9..c218a28 100644
--- a/hostsidetests/backup/AllowBackup/BackupNotAllowedApp/Android.mk
+++ b/hostsidetests/backup/AllowBackup/BackupNotAllowedApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := BackupNotAllowedApp
 
diff --git a/hostsidetests/backup/Android.mk b/hostsidetests/backup/Android.mk
index 75796a1..1faec59 100644
--- a/hostsidetests/backup/Android.mk
+++ b/hostsidetests/backup/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsBackupHostTestCases
 
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.mk b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.mk
index 5cce7a4..6155ffb 100644
--- a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.mk
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := FullBackupOnlyFalseNoAgentApp
 
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.mk b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.mk
index 3224b98..62b9860 100644
--- a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.mk
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := FullBackupOnlyFalseWithAgentApp
 
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.mk b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.mk
index 2f0eae8..8257ea7 100644
--- a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.mk
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := FullBackupOnlyTrueWithAgentApp
 
diff --git a/hostsidetests/backup/KeyValueApp/Android.mk b/hostsidetests/backup/KeyValueApp/Android.mk
index 390c6b0..d03f85f 100644
--- a/hostsidetests/backup/KeyValueApp/Android.mk
+++ b/hostsidetests/backup/KeyValueApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsKeyValueBackupRestoreApp
 
diff --git a/hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.mk b/hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.mk
index ae38548..0a0efba 100644
--- a/hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.mk
+++ b/hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsBackupRestoreAnyVersionAppUpdate
 
diff --git a/hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.mk b/hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.mk
index 277acb6..94d9376 100644
--- a/hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.mk
+++ b/hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsBackupRestoreAnyVersionNoRestoreApp
 
diff --git a/hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.mk b/hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.mk
index 170f362..81652a7 100644
--- a/hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.mk
+++ b/hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsBackupRestoreAnyVersionApp
 
diff --git a/hostsidetests/backup/SharedPreferencesRestoreApp/Android.mk b/hostsidetests/backup/SharedPreferencesRestoreApp/Android.mk
index bd6929a..4e4f0be 100644
--- a/hostsidetests/backup/SharedPreferencesRestoreApp/Android.mk
+++ b/hostsidetests/backup/SharedPreferencesRestoreApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 
 LOCAL_PACKAGE_NAME := CtsSharedPreferencesRestoreApp
 
diff --git a/hostsidetests/backup/fullbackupapp/Android.mk b/hostsidetests/backup/fullbackupapp/Android.mk
index 46af984..96f9032 100644
--- a/hostsidetests/backup/fullbackupapp/Android.mk
+++ b/hostsidetests/backup/fullbackupapp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsFullbackupApp
 
diff --git a/hostsidetests/backup/includeexcludeapp/Android.mk b/hostsidetests/backup/includeexcludeapp/Android.mk
index 9c55290..a6d258e 100644
--- a/hostsidetests/backup/includeexcludeapp/Android.mk
+++ b/hostsidetests/backup/includeexcludeapp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsIncludeExcludeApp
 
diff --git a/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java b/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
index 1d98021..75887ac 100644
--- a/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
+++ b/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
@@ -26,6 +26,7 @@
 import com.android.tradefed.targetprep.ITargetCleaner;
 import com.android.tradefed.targetprep.TargetSetupError;
 
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -51,6 +52,9 @@
     private static final String LOCAL_TRANSPORT =
             "android/com.android.internal.backup.LocalTransport";
 
+    private static final int BACKUP_PROVISIONING_TIMEOUT_SECONDS = 30;
+    private static final int BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS = 1;
+
     private boolean mIsBackupSupported;
     private boolean mWasBackupEnabled;
     private String mOldTransport;
@@ -78,6 +82,7 @@
                     mOldTransport = setBackupTransport(LOCAL_TRANSPORT);
                     CLog.d("Old transport : %s", mOldTransport);
                 }
+                waitForBackupInitialization();
             }
         }
     }
@@ -138,4 +143,26 @@
             throw new RuntimeException("non-parsable output setting bmgr transport: " + output);
         }
     }
+
+    private void waitForBackupInitialization()
+        throws TargetSetupError, DeviceNotAvailableException {
+        long tryUntilNanos = System.nanoTime()
+            + TimeUnit.SECONDS.toNanos(BACKUP_PROVISIONING_TIMEOUT_SECONDS);
+        while (System.nanoTime() < tryUntilNanos) {
+            String output = mDevice.executeShellCommand("dumpsys backup");
+            if (output.matches("(?s)"  // DOTALL
+                + "^Backup Manager is .* not pending init.*")) {
+                return;
+            }
+            try {
+                Thread.sleep(TimeUnit.SECONDS.toMillis(BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS));
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                break;
+            }
+        }
+        throw new TargetSetupError("Timed out waiting for backup initialization",
+            mDevice.getDeviceDescriptor());
+    }
+
 }
diff --git a/hostsidetests/backup/src/android/cts/backup/BaseBackupHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/BaseBackupHostSideTest.java
index 44d1aa6..e765971 100644
--- a/hostsidetests/backup/src/android/cts/backup/BaseBackupHostSideTest.java
+++ b/hostsidetests/backup/src/android/cts/backup/BaseBackupHostSideTest.java
@@ -18,6 +18,7 @@
 
 import static junit.framework.Assert.assertTrue;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.compatibility.common.tradefed.testtype.CompatibilityHostTestBase;
@@ -29,6 +30,8 @@
 import org.junit.runner.RunWith;
 
 import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Base class for CTS backup/restore hostside tests
@@ -47,6 +50,12 @@
     public void setUp() throws DeviceNotAvailableException, Exception {
         mIsBackupSupported = mDevice.hasFeature("feature:" + FEATURE_BACKUP);
         assumeTrue(mIsBackupSupported);
+
+        // Check that the backup wasn't disabled and the transport wasn't switched unexpectedly.
+        assertTrue("Backup was unexpectedly disabled during the module test run",
+                isBackupEnabled());
+        assertEquals("LocalTransport should be selected at this point", LOCAL_TRANSPORT,
+                getCurrentTransport());
     }
 
     @After
@@ -183,4 +192,28 @@
     protected void clearPackageData(String packageName) throws DeviceNotAvailableException {
         mDevice.executeShellCommand(String.format("pm clear %s", packageName));
     }
+
+    private boolean isBackupEnabled() throws DeviceNotAvailableException {
+        boolean isEnabled;
+        String output = mDevice.executeShellCommand("bmgr enabled");
+        Pattern pattern = Pattern.compile("^Backup Manager currently (enabled|disabled)$");
+        Matcher matcher = pattern.matcher(output.trim());
+        if (matcher.find()) {
+            isEnabled = "enabled".equals(matcher.group(1));
+        } else {
+            throw new RuntimeException("non-parsable output setting bmgr enabled: " + output);
+        }
+        return isEnabled;
+    }
+
+    private String getCurrentTransport() throws DeviceNotAvailableException {
+        String output = mDevice.executeShellCommand("bmgr list transports");
+        Pattern pattern = Pattern.compile("\\* (.*)");
+        Matcher matcher = pattern.matcher(output);
+        if (matcher.find()) {
+            return matcher.group(1);
+        } else {
+            throw new RuntimeException("non-parsable output setting bmgr transport: " + output);
+        }
+    }
 }
diff --git a/hostsidetests/bootstats/Android.mk b/hostsidetests/bootstats/Android.mk
index 0849f82..58fcfe2 100644
--- a/hostsidetests/bootstats/Android.mk
+++ b/hostsidetests/bootstats/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.bootstats
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/compilation/Android.mk b/hostsidetests/compilation/Android.mk
index 88339b9..09c8507 100644
--- a/hostsidetests/compilation/Android.mk
+++ b/hostsidetests/compilation/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsCompilationTestCases
 
diff --git a/hostsidetests/compilation/app/Android.mk b/hostsidetests/compilation/app/Android.mk
index d2f38db..d9d79d6 100644
--- a/hostsidetests/compilation/app/Android.mk
+++ b/hostsidetests/compilation/app/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_PACKAGE_NAME := CtsCompilationApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/content/Android.mk b/hostsidetests/content/Android.mk
index 62708f0..e60f102 100644
--- a/hostsidetests/content/Android.mk
+++ b/hostsidetests/content/Android.mk
@@ -25,7 +25,7 @@
 
 LOCAL_CTS_TEST_PACKAGE := android.content
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/Android.mk b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/Android.mk
index 84ace13..116da94 100644
--- a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/Android.mk
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/Android.mk
@@ -36,7 +36,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/Android.mk b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/Android.mk
index 7291fcd..0979e96 100644
--- a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/Android.mk
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/Android.mk
@@ -30,7 +30,7 @@
 
 LOCAL_PACKAGE_NAME := CtsSyncAccountAccessSameCertTestCases
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
index 104fdbd..92e8cdf 100644
--- a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
+++ b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_PACKAGE_NAME := CtsSyncInvalidAccountAuthorityTestCases
 
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/content/test-apps/SyncAccountAccessStubs/Android.mk b/hostsidetests/content/test-apps/SyncAccountAccessStubs/Android.mk
index fc7cd4d..c0b6fa2 100644
--- a/hostsidetests/content/test-apps/SyncAccountAccessStubs/Android.mk
+++ b/hostsidetests/content/test-apps/SyncAccountAccessStubs/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_PACKAGE_NAME := CtsSyncAccountAccessStubs
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/cpptools/Android.mk b/hostsidetests/cpptools/Android.mk
index 97329cc..8078290 100644
--- a/hostsidetests/cpptools/Android.mk
+++ b/hostsidetests/cpptools/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.tests.cpptools
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/cpptools/app/Android.mk b/hostsidetests/cpptools/app/Android.mk
index 347412a..2719cd9 100644
--- a/hostsidetests/cpptools/app/Android.mk
+++ b/hostsidetests/cpptools/app/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsCppToolsApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index 1de6b93..9cbd49e 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.adminhostside
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.mk b/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.mk
index c9bd048..0873334 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.mk
+++ b/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccountCheckAuthApp
 
@@ -34,6 +34,8 @@
     android-support-test \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := legacy-android-test
+
 LOCAL_SDK_VERSION := test_current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/NonTestOnlyOwner/Android.mk b/hostsidetests/devicepolicy/app/AccountCheck/NonTestOnlyOwner/Android.mk
index 7423d13..a8c0dbe 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/NonTestOnlyOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/AccountCheck/NonTestOnlyOwner/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccountCheckNonTestOnlyOwnerApp
 
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwner/Android.mk b/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwner/Android.mk
index 7a8c0b7..c502fe8 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwner/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccountCheckTestOnlyOwnerApp
 
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwnerUpdate/Android.mk b/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwnerUpdate/Android.mk
index 57f011e..c05d9d1 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwnerUpdate/Android.mk
+++ b/hostsidetests/devicepolicy/app/AccountCheck/TestOnlyOwnerUpdate/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccountCheckTestOnlyOwnerUpdateApp
 
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.mk b/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.mk
index 752ae96..d66c6bd 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.mk
+++ b/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccountCheckAuthAppTester
 
diff --git a/hostsidetests/devicepolicy/app/AccountManagement/Android.mk b/hostsidetests/devicepolicy/app/AccountManagement/Android.mk
index cd3aa98..b7d99bf 100644
--- a/hostsidetests/devicepolicy/app/AccountManagement/Android.mk
+++ b/hostsidetests/devicepolicy/app/AccountManagement/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccountManagementDevicePolicyApp
 
diff --git a/hostsidetests/devicepolicy/app/Android.mk b/hostsidetests/devicepolicy/app/Android.mk
index a22ef3f..d44e88e 100644
--- a/hostsidetests/devicepolicy/app/Android.mk
+++ b/hostsidetests/devicepolicy/app/Android.mk
@@ -17,4 +17,4 @@
 include $(CLEAR_VARS)
 
 # Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.mk b/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.mk
index 946a763..81b63b2 100644
--- a/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.mk
@@ -27,6 +27,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/Assistant/Android.mk b/hostsidetests/devicepolicy/app/Assistant/Android.mk
index 196f323..86144a2 100644
--- a/hostsidetests/devicepolicy/app/Assistant/Android.mk
+++ b/hostsidetests/devicepolicy/app/Assistant/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDevicePolicyAssistApp
 
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/AutofillApp/Android.mk b/hostsidetests/devicepolicy/app/AutofillApp/Android.mk
index 940c4a8..522b196 100644
--- a/hostsidetests/devicepolicy/app/AutofillApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/AutofillApp/Android.mk
@@ -25,13 +25,13 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDevicePolicyAutofillApp
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/Android.mk b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
index fa84415..23eb1f7 100644
--- a/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
+++ b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
@@ -29,6 +29,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.mk b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.mk
index 06c1f87..eec2e12 100644
--- a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.mk
+++ b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.mk
@@ -25,13 +25,13 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsContactDirectoryProvider
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
index 05db43a..c8872b4 100644
--- a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
@@ -64,7 +64,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.cts.comp2 \
                     --rename-instrumentation-target-package com.android.cts.comp2
 
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk b/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
index cb54cd7..1e6e2f1 100644
--- a/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
@@ -16,7 +16,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsCustomizationApp
 
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CustomizationApp/AndroidManifest.xml
index f638adf..4b20829 100644
--- a/hostsidetests/devicepolicy/app/CustomizationApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/AndroidManifest.xml
@@ -19,6 +19,7 @@
 
     <uses-sdk android:minSdkVersion="24"/>
 
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
 
     <application>
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/Android.mk b/hostsidetests/devicepolicy/app/DelegateApp/Android.mk
index fc316e6..a46eed8 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/DelegateApp/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAdmin/api23/Android.mk b/hostsidetests/devicepolicy/app/DeviceAdmin/api23/Android.mk
index 7d277d9..a8f4f05 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdmin/api23/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAdmin/api23/Android.mk
@@ -31,9 +31,11 @@
     compatibility-device-util \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := legacy-android-test
+
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAdmin/api24/Android.mk b/hostsidetests/devicepolicy/app/DeviceAdmin/api24/Android.mk
index ab38265..4e2cfb6 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdmin/api24/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAdmin/api24/Android.mk
@@ -31,9 +31,11 @@
     compatibility-device-util \
     legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := legacy-android-test
+
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package1/Android.mk b/hostsidetests/devicepolicy/app/DeviceAdminService/package1/Android.mk
index e874b8b..72d2bb0 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package1/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package1/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package2/Android.mk b/hostsidetests/devicepolicy/app/DeviceAdminService/package2/Android.mk
index 1e4b9c7..e2f9b8d 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package2/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package2/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package3/Android.mk b/hostsidetests/devicepolicy/app/DeviceAdminService/package3/Android.mk
index 6ee4acf..b88d537 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package3/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package3/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/package4/Android.mk b/hostsidetests/devicepolicy/app/DeviceAdminService/package4/Android.mk
index 68dc546..7f72ddf 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/package4/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/package4/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/Android.mk b/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/Android.mk
index 0207110..8c66638 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/packageb/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
index f8467c1..c818856 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
-LOCAL_JAVA_LIBRARIES = conscrypt
+LOCAL_JAVA_LIBRARIES = conscrypt legacy-android-test
 
 LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 compatibility-device-util ctstestrunner ub-uiautomator
 
@@ -33,6 +33,6 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk
index 8a0d559..1c50763 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
-LOCAL_JAVA_LIBRARIES = conscrypt
+LOCAL_JAVA_LIBRARIES = conscrypt legacy-android-test
 
 LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 compatibility-device-util ctstestrunner ub-uiautomator
 
@@ -33,6 +33,6 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
index d3a78d2..81a23d2 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
@@ -33,6 +33,6 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
index 93c052f..0dc8bc3 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
 
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
index 01a5a3a..84330ab 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
@@ -16,14 +16,14 @@
 
 package com.android.cts.deviceandprofileowner;
 
+import static com.android.cts.deviceandprofileowner.vpn.VpnTestHelper.TEST_ADDRESS;
+import static com.android.cts.deviceandprofileowner.vpn.VpnTestHelper.VPN_PACKAGE;
+
 import android.os.Bundle;
 import android.os.UserManager;
 
 import com.android.cts.deviceandprofileowner.vpn.VpnTestHelper;
 
-import static com.android.cts.deviceandprofileowner.vpn.VpnTestHelper.VPN_PACKAGE;
-import static com.android.cts.deviceandprofileowner.vpn.VpnTestHelper.TEST_ADDRESS;
-
 /**
  * Validates that a device owner or profile owner can set an always-on VPN without user action.
  *
@@ -46,6 +46,8 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
+        // always-on is null by default
+        assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
         mPackageName = mContext.getPackageName();
     }
 
@@ -95,9 +97,6 @@
     }
 
     public void testSetNonVpnAlwaysOn() throws Exception {
-        // test always-on is null by default
-        assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
-
         // Treat this CTS DPC as an non-vpn app, since it doesn't register
         // android.net.VpnService intent filter in AndroidManifest.xml.
         try {
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnUnsupportedTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnUnsupportedTest.java
new file mode 100644
index 0000000..03f8be2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnUnsupportedTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.cts.deviceandprofileowner;
+
+import static com.android.cts.deviceandprofileowner.vpn.VpnTestHelper.VPN_PACKAGE;
+
+/**
+ * Validates that a device owner or profile owner cannot enable the always-on feature for
+ * unsupported VPN apps.
+ *
+ * A VPN app does not support the always-on feature if it
+ * <ul>
+ *     <li>has a target SDK version below {@link android.os.Build.VERSION_CODES#N}, or</li>
+ *     <li>explicitly opts out of the feature through
+ *         {@link android.net.VpnService#METADATA_SUPPORTS_ALWAYS_ON}</li>
+ * </ul>
+ */
+public class AlwaysOnVpnUnsupportedTest extends BaseDeviceAdminTest {
+
+    public void testAssertNoAlwaysOnVpn() throws Exception {
+        assertNull("Always-on VPN already exists",
+                mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
+    }
+
+    public void testClearAlwaysOnVpn() throws Exception {
+        mDevicePolicyManager.setAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT, null, false);
+        assertNull("Failed to clear always-on package",
+                mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
+    }
+
+    public void testSetSupportedVpnAlwaysOn() throws Exception {
+        testAssertNoAlwaysOnVpn();
+        mDevicePolicyManager.setAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, true);
+        assertEquals("Failed to set always-on package",
+                VPN_PACKAGE, mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
+    }
+
+    public void testSetUnsupportedVpnAlwaysOn() throws Exception {
+        testAssertNoAlwaysOnVpn();
+        try {
+            mDevicePolicyManager.setAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, true);
+            fail("setAlwaysOnVpnPackage should not accept an unsupported vpn package");
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+        assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java
index 8babe14..5728cf6 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java
@@ -17,6 +17,7 @@
 package com.android.cts.deviceandprofileowner;
 
 import static android.provider.Settings.Secure.AUTOFILL_SERVICE;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 
 import android.content.Intent;
 import static android.os.UserManager.DISALLOW_AUTOFILL;
@@ -28,9 +29,6 @@
     private static final String AUTOFILL_PACKAGE_NAME = "com.android.cts.devicepolicy.autofillapp";
     private static final String AUTOFILL_ACTIVITY_NAME = AUTOFILL_PACKAGE_NAME + ".SimpleActivity";
 
-    // TODO: should static import Settings.Secure instead, but that's not a @TestApi
-    private static String USER_SETUP_COMPLETE = "user_setup_complete";
-
     // Currently, autofill_service is a cloned service, so it's only set in the default user.
     // That might change, so we're using a guard to decide how to set it
     private final boolean USES_CLONED_SETTINGS = true;
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index a4cd12c..4cc041a 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -36,6 +36,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk b/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
index ce3c537..08edf44 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
index 0fc0564..b71ddfb 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
index 5bb5c80..ed4943f 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+LOCAL_JAVA_LIBRARIES := legacy-android-test cts-junit
 
 LOCAL_STATIC_JAVA_LIBRARIES = \
 	android-support-v4 \
@@ -35,6 +35,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
index 95b3e27..932f691 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
@@ -24,11 +24,11 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+LOCAL_JAVA_LIBRARIES := cts-junit
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index ce366d9..b947a61 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
@@ -38,6 +38,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NotificationListenerTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NotificationListenerTest.java
index d4cbae7..499e710 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NotificationListenerTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NotificationListenerTest.java
@@ -60,11 +60,8 @@
     private final LocalBroadcastReceiver mReceiver = new LocalBroadcastReceiver();
     private Context mContext;
     private DevicePolicyManager mDpm;
-    private NotificationManager mNotificationManager;
     private UiDevice mDevice;
     private int mProfileUserId;
-    private String mPreviousListeners;
-    private boolean mChangedListeners;
 
     @Before
     public void setUp() throws Exception {
@@ -82,16 +79,7 @@
     @After
     public void tearDown() throws Exception {
         LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mReceiver);
-        if (mChangedListeners) {
-            if (mPreviousListeners != null) {
-                mDevice.executeShellCommand(
-                        "settings put secure enabled_notification_listeners "
-                        + mPreviousListeners);
-            } else {
-                mDevice.executeShellCommand(
-                        "settings delete secure enabled_notification_listeners");
-            }
-        }
+        toggleNotificationListener(false);
     }
 
     @Test
@@ -116,7 +104,7 @@
 
     @Test
     public void testCanReceiveNotifications() throws Exception {
-        enableNotificationListener();
+        toggleNotificationListener(true);
 
         sendProfileNotification();
         assertTrue(mReceiver.waitForNotificationPostedReceived());
@@ -133,7 +121,7 @@
 
     @Test
     public void testCannotReceiveProfileNotifications() throws Exception {
-        enableNotificationListener();
+        toggleNotificationListener(true);
 
         sendProfileNotification();
         // Don't see notification or cancellation from work profile.
@@ -174,28 +162,14 @@
                 + SENDER_COMPONENT);
     }
 
-    private void enableNotificationListener() throws Exception {
-        String listeners = mDevice.executeShellCommand(
-                "settings get secure enabled_notification_listeners").trim();
-        if (listeners.equals("null")) {
-            listeners = null;
-        }
+    private void toggleNotificationListener(boolean enable) throws Exception {
         String testListener = new ComponentName(
                 mContext, CrossProfileNotificationListenerService.class).flattenToString();
-
-        if (listeners == null || !listeners.contains(testListener)) {
-            mPreviousListeners = listeners;
-            mChangedListeners = true;
-            String newListeners;
-            if (listeners != null && listeners.length() > 0) {
-                newListeners = listeners + ":" + testListener;
-            } else {
-                newListeners = testListener;
-            }
-            mDevice.executeShellCommand(
-                    "settings put secure enabled_notification_listeners "
-                    + newListeners);
-            Log.i(TAG, "Enabled notification listener " + testListener);
+        mDevice.executeShellCommand("cmd notification "
+                + (enable ?  "allow_listener " : "disallow_listener ")
+                + testListener);
+        Log.i(TAG, "Toggled notification listener state" + testListener + " to state " + enable);
+        if (enable) {
             assertTrue(mReceiver.waitForListenerConnected());
         }
     }
diff --git a/hostsidetests/devicepolicy/app/NotificationSender/Android.mk b/hostsidetests/devicepolicy/app/NotificationSender/Android.mk
index 8b85e66..8c7633e 100644
--- a/hostsidetests/devicepolicy/app/NotificationSender/Android.mk
+++ b/hostsidetests/devicepolicy/app/NotificationSender/Android.mk
@@ -25,13 +25,13 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsNotificationSenderApp
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
index 5cf5e66..11680e9 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk b/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk
index 135b4cf..34b8e08 100644
--- a/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/Android.mk b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
index 46b6292..f0007db 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
@@ -25,13 +25,13 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsSimpleApp
 
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
index 649c3ab..deb5320 100644
--- a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := 21
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SingleAdminApp/Android.mk b/hostsidetests/devicepolicy/app/SingleAdminApp/Android.mk
index 6b2609b..426dbf2 100644
--- a/hostsidetests/devicepolicy/app/SingleAdminApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/SingleAdminApp/Android.mk
@@ -37,6 +37,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
index ac967a3..1a804b8 100644
--- a/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
@@ -27,6 +27,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
index 8992f42..b03cf95 100644
--- a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 6ab4024..54c86f6 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -84,6 +84,9 @@
 
     private static final String VPN_APP_PKG = "com.android.cts.vpnfirewall";
     private static final String VPN_APP_APK = "CtsVpnFirewallApp.apk";
+    private static final String VPN_APP_API23_APK = "CtsVpnFirewallAppApi23.apk";
+    private static final String VPN_APP_API24_APK = "CtsVpnFirewallAppApi24.apk";
+    private static final String VPN_APP_NOT_ALWAYS_ON_APK = "CtsVpnFirewallAppNotAlwaysOn.apk";
 
     private static final String COMMAND_BLOCK_ACCOUNT_TYPE = "block-accounttype";
     private static final String COMMAND_UNBLOCK_ACCOUNT_TYPE = "unblock-accounttype";
@@ -123,6 +126,9 @@
             getDevice().uninstallPackage(DELEGATE_APP_PKG);
             getDevice().uninstallPackage(ACCOUNT_MANAGEMENT_PKG);
             getDevice().uninstallPackage(VPN_APP_PKG);
+            getDevice().uninstallPackage(VPN_APP_API23_APK);
+            getDevice().uninstallPackage(VPN_APP_API24_APK);
+            getDevice().uninstallPackage(VPN_APP_NOT_ALWAYS_ON_APK);
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
             getDevice().uninstallPackage(INTENT_SENDER_PKG);
             getDevice().uninstallPackage(CUSTOMIZATION_APP_PKG);
@@ -294,6 +300,49 @@
         }
     }
 
+    @RequiresDevice
+    public void testAlwaysOnVpnUnsupportedPackage() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        try {
+            // Target SDK = 23: unsupported
+            installAppAsUser(VPN_APP_API23_APK, mUserId);
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetUnsupportedVpnAlwaysOn");
+
+            // Target SDK = 24: supported
+            installAppAsUser(VPN_APP_API24_APK, mUserId);
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetSupportedVpnAlwaysOn");
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testClearAlwaysOnVpn");
+
+            // Explicit opt-out: unsupported
+            installAppAsUser(VPN_APP_NOT_ALWAYS_ON_APK, mUserId);
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetUnsupportedVpnAlwaysOn");
+        } finally {
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testClearAlwaysOnVpn");
+        }
+    }
+
+    @RequiresDevice
+    public void testAlwaysOnVpnUnsupportedPackageReplaced() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        try {
+            // Target SDK = 24: supported
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testAssertNoAlwaysOnVpn");
+            installAppAsUser(VPN_APP_API24_APK, mUserId);
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetSupportedVpnAlwaysOn");
+            // Update the app to target higher API level, but with manifest opt-out
+            installAppAsUser(VPN_APP_NOT_ALWAYS_ON_APK, mUserId);
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testAssertNoAlwaysOnVpn");
+        } finally {
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testClearAlwaysOnVpn");
+        }
+    }
+
     public void testPermissionPolicy() throws Exception {
         if (!mHasFeature) {
             return;
@@ -714,7 +763,14 @@
         if (!mHasFeature) {
             return;
         }
-        executeDeviceTestMethod(".ResetPasswordWithTokenTest", "testResetPasswordWithToken");
+        // If ResetPasswordWithTokenTest for managed profile is executed before device owner and
+        // primary user profile owner tests, password reset token would have been disabled for
+        // the primary user, so executing ResetPasswordWithTokenTest on user 0 would fail. We allow
+        // this and do not fail the test in this case.
+        // This is the default test for MixedDeviceOwnerTest and MixedProfileOwnerTest,
+        // MixedManagedProfileOwnerTest overrides this method to execute the same test more strictly
+        // without allowing failures.
+        executeDeviceTestMethod(".ResetPasswordWithTokenTest", "testResetPasswordWithTokenMayFail");
     }
 
     protected void executeDeviceTestClass(String className) throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 0022804..4bdeae9 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -137,4 +137,24 @@
         super.testAlwaysOnVpnPackageUninstalled();
     }
 
+    @Override
+    public void testAlwaysOnVpnUnsupportedPackage() throws Exception {
+        super.testAlwaysOnVpnUnsupportedPackage();
+    }
+
+    @Override
+    public void testAlwaysOnVpnUnsupportedPackageReplaced() throws Exception {
+        super.testAlwaysOnVpnUnsupportedPackageReplaced();
+    }
+
+    @Override
+    public void testResetPasswordWithToken() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        // Execute the test method that's guaranteed to succeed. See also test in base class
+        // which are tolerant to failure and executed by MixedDeviceOwnerTest and
+        // MixedProfileOwnerTest
+        executeDeviceTestMethod(".ResetPasswordWithTokenTest", "testResetPasswordWithToken");
+    }
 }
diff --git a/hostsidetests/dumpsys/Android.mk b/hostsidetests/dumpsys/Android.mk
index 1b3768c..d15996c 100644
--- a/hostsidetests/dumpsys/Android.mk
+++ b/hostsidetests/dumpsys/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.dumpsys
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/dumpsys/apps/FramestatsTestApp/Android.mk b/hostsidetests/dumpsys/apps/FramestatsTestApp/Android.mk
index a20895d..ff34e63 100644
--- a/hostsidetests/dumpsys/apps/FramestatsTestApp/Android.mk
+++ b/hostsidetests/dumpsys/apps/FramestatsTestApp/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_PACKAGE_NAME := CtsFramestatsTestApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.mk b/hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.mk
index f438d83..3f7bd08 100644
--- a/hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.mk
+++ b/hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+LOCAL_JAVA_LIBRARIES := cts-junit
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.mk b/hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.mk
index eff16cf..9b2e198 100644
--- a/hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.mk
+++ b/hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/edi/Android.mk b/hostsidetests/edi/Android.mk
index efa093f..c3b07ec 100644
--- a/hostsidetests/edi/Android.mk
+++ b/hostsidetests/edi/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsEdiHostTestCases
 
diff --git a/hostsidetests/incident/Android.mk b/hostsidetests/incident/Android.mk
index 05a6353..b89bafe 100644
--- a/hostsidetests/incident/Android.mk
+++ b/hostsidetests/incident/Android.mk
@@ -20,7 +20,7 @@
 
 # tag this module as a cts test artifact
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsIncidentHostTestCases
 
diff --git a/hostsidetests/incident/apps/batterystatsapp/Android.mk b/hostsidetests/incident/apps/batterystatsapp/Android.mk
index bf1858c..42c87f4 100644
--- a/hostsidetests/incident/apps/batterystatsapp/Android.mk
+++ b/hostsidetests/incident/apps/batterystatsapp/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
index 5e1198f..74dfd11 100644
--- a/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
+++ b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
@@ -25,6 +25,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.READ_SYNC_STATS" />
     <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
 
     <application android:label="@string/app_name">
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
index 65237f9..e414d2d 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
@@ -32,6 +32,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Color;
+import android.graphics.Point;
 import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
@@ -42,6 +44,10 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
 
 
 import org.junit.Assert;
@@ -53,6 +59,8 @@
 public class BatteryStatsBgVsFgActions {
     private static final String TAG = BatteryStatsBgVsFgActions.class.getSimpleName();
 
+    private static final int DO_NOTHING_TIMEOUT = 2000;
+
     public static final String KEY_ACTION = "action";
     public static final String ACTION_BLE_SCAN_OPTIMIZED = "action.ble_scan_optimized";
     public static final String ACTION_BLE_SCAN_UNOPTIMIZED = "action.ble_scan_unoptimized";
@@ -62,6 +70,9 @@
     public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
     public static final String ACTION_WIFI_DOWNLOAD = "action.wifi_download";
     public static final String ACTION_WIFI_UPLOAD = "action.wifi_upload";
+    public static final String ACTION_SLEEP_WHILE_BACKGROUND = "action.sleep_background";
+    public static final String ACTION_SLEEP_WHILE_TOP = "action.sleep_top";
+    public static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
 
     public static final String KEY_REQUEST_CODE = "request_code";
 
@@ -100,12 +111,49 @@
             case ACTION_WIFI_UPLOAD:
                 doWifiUpload(ctx, requestCode);
                 break;
+            case ACTION_SLEEP_WHILE_BACKGROUND:
+                sleep(DO_NOTHING_TIMEOUT);
+                tellHostActionFinished(ACTION_SLEEP_WHILE_BACKGROUND, requestCode);
+                break;
+            case ACTION_SLEEP_WHILE_TOP:
+                doNothingAsync(ctx, ACTION_SLEEP_WHILE_TOP, requestCode);
+                break;
+            case ACTION_SHOW_APPLICATION_OVERLAY:
+                showApplicationOverlay(ctx, requestCode);
+                break;
             default:
                 Log.e(TAG, "Intent had invalid action");
         }
         sleep(100);
     }
 
+    private static void showApplicationOverlay(Context ctx, String requestCode) {
+        final WindowManager wm = ctx.getSystemService(WindowManager.class);
+        Point size = new Point();
+        wm.getDefaultDisplay().getSize(size);
+
+        WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+        wmlp.width = size.x / 4;
+        wmlp.height = size.y / 4;
+        wmlp.gravity = Gravity.CENTER | Gravity.LEFT;
+        wmlp.setTitle(ctx.getPackageName());
+
+        ViewGroup.LayoutParams vglp = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+
+        View v = new View(ctx);
+        v.setBackgroundColor(Color.GREEN);
+        v.setLayoutParams(vglp);
+        wm.addView(v, wmlp);
+
+        tellHostActionFinished(ACTION_SHOW_APPLICATION_OVERLAY, requestCode);
+    }
+
     private static void doOptimizedBleScan(Context ctx, String requestCode) {
         ScanSettings scanSettings = new ScanSettings.Builder()
                 .setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC).build();
@@ -229,6 +277,24 @@
         }.execute();
     }
 
+    private static void doNothingAsync(Context ctx, String requestCode, String actionCode) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                sleep(DO_NOTHING_TIMEOUT);
+                return null;
+            }
+
+            @Override
+            protected void onPostExecute(Void nothing) {
+                if (ctx instanceof Activity) {
+                    ((Activity) ctx).finish();
+                    tellHostActionFinished(actionCode, requestCode);
+                }
+            }
+        }.execute();
+    }
+
     private static void doSync(Context ctx, String requestCode) {
         BatteryStatsAuthenticator.removeAllAccounts(ctx);
         final Account account = BatteryStatsAuthenticator.getTestAccount();
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
index 5622e40..da00afc 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.server.cts.device.batterystats;
 
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.ACTION_SLEEP_WHILE_TOP;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.ACTION_SYNC;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.KEY_ACTION;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.KEY_REQUEST_CODE;
@@ -49,9 +50,17 @@
 
         doAction(this, action, requestCode);
 
-        // ACTION_SYNC will finish itself. Others get finished here.
-        if (!ACTION_SYNC.equals(action)) {
+        if (!isActionAsync(action)) {
             finish();
         }
     }
+
+    private boolean isActionAsync(String action) {
+        switch (action) {
+            case ACTION_SYNC:
+            case ACTION_SLEEP_WHILE_TOP:
+                return true;
+        }
+        return false;
+    }
 }
diff --git a/hostsidetests/incident/apps/boundwidgetapp/Android.mk b/hostsidetests/incident/apps/boundwidgetapp/Android.mk
index 160f5d0..152414f 100644
--- a/hostsidetests/incident/apps/boundwidgetapp/Android.mk
+++ b/hostsidetests/incident/apps/boundwidgetapp/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/incident/apps/errorsapp/Android.mk b/hostsidetests/incident/apps/errorsapp/Android.mk
index 87b9857..191e9b7 100644
--- a/hostsidetests/incident/apps/errorsapp/Android.mk
+++ b/hostsidetests/incident/apps/errorsapp/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/Android.mk b/hostsidetests/incident/apps/graphicsstatsapp/Android.mk
index ce3ea11..c2812c0 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/Android.mk
+++ b/hostsidetests/incident/apps/graphicsstatsapp/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/hostsidetests/incident/apps/netstatsapp/Android.mk b/hostsidetests/incident/apps/netstatsapp/Android.mk
index 88ae35c..83ae82f 100644
--- a/hostsidetests/incident/apps/netstatsapp/Android.mk
+++ b/hostsidetests/incident/apps/netstatsapp/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/incident/apps/storagedapp/Android.mk b/hostsidetests/incident/apps/storagedapp/Android.mk
index 69d597e..3028716 100644
--- a/hostsidetests/incident/apps/storagedapp/Android.mk
+++ b/hostsidetests/incident/apps/storagedapp/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
index 601c9024..6705b60 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -20,7 +20,6 @@
 
 import com.google.common.base.Charsets;
 
-import java.util.Arrays;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -52,6 +51,18 @@
     public static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
     public static final String FEATURE_WIFI = "android.hardware.wifi";
 
+    private static final int STATE_TIME_TOP_INDEX = 4;
+    private static final int STATE_TIME_FOREGROUND_SERVICE_INDEX = 5;
+    private static final int STATE_TIME_FOREGROUND_INDEX = 7;
+    private static final int STATE_TIME_BACKGROUND_INDEX = 8;
+    private static final int STATE_TIME_CACHED_INDEX = 9;
+
+    private static final long TIME_SPENT_IN_TOP = 2000;
+    private static final long TIME_SPENT_IN_FOREGROUND = 2000;
+    private static final long TIME_SPENT_IN_BACKGROUND = 2000;
+    private static final long TIME_SPENT_IN_CACHED = 2000;
+    private static final long SCREEN_STATE_CHANGE_TIMEOUT = 4000;
+    private static final long SCREEN_STATE_POLLING_INTERVAL = 500;
 
     // Low end of packet size. TODO: Get exact packet size
     private static final int LOW_MTU = 1500;
@@ -68,6 +79,9 @@
     public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
     public static final String ACTION_WIFI_DOWNLOAD = "action.wifi_download";
     public static final String ACTION_WIFI_UPLOAD = "action.wifi_upload";
+    public static final String ACTION_SLEEP_WHILE_BACKGROUND = "action.sleep_background";
+    public static final String ACTION_SLEEP_WHILE_TOP = "action.sleep_top";
+    public static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
 
     public static final String KEY_REQUEST_CODE = "request_code";
     public static final String BG_VS_FG_TAG = "BatteryStatsBgVsFgActions";
@@ -103,6 +117,13 @@
         getDevice().executeShellCommand("wm dismiss-keyguard");
     }
 
+    /**
+     * This will send the screen to sleep
+     */
+    protected void turnScreenOffForReal() throws Exception {
+        getDevice().executeShellCommand("input keyevent KEYCODE_SLEEP");
+    }
+
     protected void batteryOnScreenOn() throws Exception {
         getDevice().executeShellCommand("dumpsys battery unplug");
         getDevice().executeShellCommand("dumpsys batterystats disable pretend-screen-off");
@@ -156,20 +177,109 @@
         batteryOffScreenOn();
     }
 
+    private void startSimpleActivity() throws Exception {
+        getDevice().executeShellCommand(
+                "am start -n com.android.server.cts.device.batterystats/.SimpleActivity");
+    }
+
     public void testServiceForegroundDuration() throws Exception {
         batteryOnScreenOff();
         installPackage(DEVICE_SIDE_TEST_APK, true);
 
-        getDevice().executeShellCommand(
-                "am start -n com.android.server.cts.device.batterystats/.SimpleActivity");
-        assertValueRange("st", "", 5, 0, 0); // No foreground service time before test
+        startSimpleActivity();
+        assertValueRange("st", "", STATE_TIME_FOREGROUND_SERVICE_INDEX, 0,
+                0); // No foreground service time before test
         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsProcessStateTests",
                 "testForegroundService");
-        assertValueRange("st", "", 5, (long) (2000 * 0.8), 4000);
-
+        assertValueRange("st", "", STATE_TIME_FOREGROUND_SERVICE_INDEX, (long) (2000 * 0.8), 4000);
         batteryOffScreenOn();
     }
 
+    public void testUidForegroundDuration() throws Exception {
+        batteryOnScreenOff();
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+        // No foreground time before test
+        assertValueRange("st", "", STATE_TIME_FOREGROUND_INDEX, 0, 0);
+        turnScreenOnForReal();
+        assertScreenOn();
+        executeForeground(ACTION_SHOW_APPLICATION_OVERLAY, 2000);
+        Thread.sleep(TIME_SPENT_IN_FOREGROUND); // should be in foreground for about this long
+        assertApproximateTimeInState(STATE_TIME_FOREGROUND_INDEX, TIME_SPENT_IN_FOREGROUND);
+        batteryOffScreenOn();
+    }
+
+    public void testUidBackgroundDuration() throws Exception {
+        batteryOnScreenOff();
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+        // No background time before test
+        assertValueRange("st", "", STATE_TIME_BACKGROUND_INDEX, 0, 0);
+        executeBackground(ACTION_SLEEP_WHILE_BACKGROUND, 4000);
+        assertApproximateTimeInState(STATE_TIME_BACKGROUND_INDEX, TIME_SPENT_IN_BACKGROUND);
+        batteryOffScreenOn();
+    }
+
+    public void testTopDuration() throws Exception {
+        batteryOnScreenOff();
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+        // No top time before test
+        assertValueRange("st", "", STATE_TIME_TOP_INDEX, 0, 0);
+        turnScreenOnForReal();
+        assertScreenOn();
+        executeForeground(ACTION_SLEEP_WHILE_TOP, 4000);
+        assertApproximateTimeInState(STATE_TIME_TOP_INDEX, TIME_SPENT_IN_TOP);
+        batteryOffScreenOn();
+    }
+
+    public void testCachedDuration() throws Exception {
+        batteryOnScreenOff();
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+        // No cached time before test
+        assertValueRange("st", "", STATE_TIME_CACHED_INDEX, 0, 0);
+        startSimpleActivity();
+        Thread.sleep(TIME_SPENT_IN_CACHED); // process should be in cached state for about this long
+        assertApproximateTimeInState(STATE_TIME_CACHED_INDEX, TIME_SPENT_IN_CACHED);
+        batteryOffScreenOn();
+    }
+
+    private void assertScreenOff() throws Exception {
+        final long deadLine = System.currentTimeMillis() + SCREEN_STATE_CHANGE_TIMEOUT;
+        boolean screenAwake = true;
+        do {
+            final String dumpsysPower = getDevice().executeShellCommand("dumpsys power").trim();
+            for (String line : dumpsysPower.split("\n")) {
+                if (line.contains("Display Power")) {
+                    screenAwake = line.trim().endsWith("ON");
+                    break;
+                }
+            }
+            Thread.sleep(SCREEN_STATE_POLLING_INTERVAL);
+        } while (screenAwake && System.currentTimeMillis() < deadLine);
+        assertFalse("Screen could not be turned off", screenAwake);
+    }
+
+    private void assertScreenOn() throws Exception {
+        // this also checks that the keyguard is dismissed
+        final long deadLine = System.currentTimeMillis() + SCREEN_STATE_CHANGE_TIMEOUT;
+        boolean screenAwake;
+        do {
+            final String dumpsysWindowPolicy =
+                    getDevice().executeShellCommand("dumpsys window policy").trim();
+            boolean keyguardStateLines = false;
+            screenAwake = true;
+            for (String line : dumpsysWindowPolicy.split("\n")) {
+                if (line.contains("KeyguardServiceDelegate")) {
+                    keyguardStateLines = true;
+                } else if (keyguardStateLines && line.contains("showing=")) {
+                    screenAwake &= line.trim().endsWith("false");
+                } else if (keyguardStateLines && line.contains("screenState=")) {
+                    screenAwake &= line.trim().endsWith("2");
+                }
+            }
+            Thread.sleep(SCREEN_STATE_POLLING_INTERVAL);
+        } while (!screenAwake && System.currentTimeMillis() < deadLine);
+        assertTrue("Screen could not be turned on", screenAwake);
+    }
+
     public void testBleScans() throws Exception {
         if (isTV() || !hasFeature(FEATURE_BLUETOOTH_LE, true)) {
             return;
@@ -475,6 +585,10 @@
         return uid;
     }
 
+    private void assertApproximateTimeInState(int index, long duration) throws Exception {
+        assertValueRange("st", "", index, (long) (0.8 * duration), 2 * duration);
+    }
+
     /**
      * Verifies that the recorded time for the specified tag and name in the test package
      * is within the specified range.
@@ -483,7 +597,6 @@
             int index, long min, long max) throws Exception {
         int uid = getUid();
         long value = getLongValue(uid, tag, optionalAfterTag, index);
-
         assertTrue("Value " + value + " is less than min " + min, value >= min);
         assertTrue("Value " + value + " is greater than max " + max, value <= max);
     }
diff --git a/hostsidetests/inputmethodservice/common/Android.mk b/hostsidetests/inputmethodservice/common/Android.mk
index 67b8f9d..0e50a9c 100644
--- a/hostsidetests/inputmethodservice/common/Android.mk
+++ b/hostsidetests/inputmethodservice/common/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsInputMethodServiceCommon
 
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/Android.mk b/hostsidetests/inputmethodservice/deviceside/devicetest/Android.mk
index 1986e5a..db742bf 100644
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/Android.mk
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/Android.mk
@@ -36,7 +36,7 @@
     CtsInputMethodServiceLib
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsInputMethodServiceDeviceTests
 
diff --git a/hostsidetests/inputmethodservice/deviceside/ime1/Android.mk b/hostsidetests/inputmethodservice/deviceside/ime1/Android.mk
index c573ea4..6a74124 100644
--- a/hostsidetests/inputmethodservice/deviceside/ime1/Android.mk
+++ b/hostsidetests/inputmethodservice/deviceside/ime1/Android.mk
@@ -32,7 +32,7 @@
     CtsInputMethodServiceLib
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsInputMethod1
 
diff --git a/hostsidetests/inputmethodservice/deviceside/ime2/Android.mk b/hostsidetests/inputmethodservice/deviceside/ime2/Android.mk
index dbbb460..a371c83 100644
--- a/hostsidetests/inputmethodservice/deviceside/ime2/Android.mk
+++ b/hostsidetests/inputmethodservice/deviceside/ime2/Android.mk
@@ -32,7 +32,7 @@
     CtsInputMethodServiceLib
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsInputMethod2
 
diff --git a/hostsidetests/inputmethodservice/deviceside/lib/Android.mk b/hostsidetests/inputmethodservice/deviceside/lib/Android.mk
index 6977d6b..9fdcec6 100644
--- a/hostsidetests/inputmethodservice/deviceside/lib/Android.mk
+++ b/hostsidetests/inputmethodservice/deviceside/lib/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsInputMethodServiceLib
 
diff --git a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk b/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
index 61a7574..2261a79 100644
--- a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
+++ b/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
@@ -31,7 +31,7 @@
     CtsInputMethodServiceLib
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsInputMethodServiceEventProvider
 
diff --git a/hostsidetests/inputmethodservice/hostside/Android.mk b/hostsidetests/inputmethodservice/hostside/Android.mk
index 68b4498..5ff22a2 100644
--- a/hostsidetests/inputmethodservice/hostside/Android.mk
+++ b/hostsidetests/inputmethodservice/hostside/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsInputMethodServiceHostTestCases
 
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
index c57559b..c740f61 100644
--- a/hostsidetests/jdwpsecurity/Android.mk
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CTS_TEST_PACKAGE := android.host.jdwpsecurity
 
diff --git a/hostsidetests/jdwpsecurity/app/Android.mk b/hostsidetests/jdwpsecurity/app/Android.mk
index eae6088..e1523ab 100644
--- a/hostsidetests/jdwpsecurity/app/Android.mk
+++ b/hostsidetests/jdwpsecurity/app/Android.mk
@@ -19,5 +19,5 @@
 LOCAL_MODULE := CtsJdwpApp
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 include $(BUILD_JAVA_LIBRARY)
diff --git a/hostsidetests/jvmti/allocation-tracking/Android.mk b/hostsidetests/jvmti/allocation-tracking/Android.mk
index 511f543..582927a 100644
--- a/hostsidetests/jvmti/allocation-tracking/Android.mk
+++ b/hostsidetests/jvmti/allocation-tracking/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiTrackingHostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/allocation-tracking/app/Android.mk b/hostsidetests/jvmti/allocation-tracking/app/Android.mk
index 7b40a4f..a5fd7c3 100644
--- a/hostsidetests/jvmti/allocation-tracking/app/Android.mk
+++ b/hostsidetests/jvmti/allocation-tracking/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/hostsidetests/jvmti/attaching/Android.mk
similarity index 68%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to hostsidetests/jvmti/attaching/Android.mk
index 151379b..38e1a4f 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/hostsidetests/jvmti/attaching/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -14,13 +14,4 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk b/hostsidetests/jvmti/attaching/app/Android.mk
similarity index 78%
copy from hostsidetests/jvmti/run-tests/test-981/app/Android.mk
copy to hostsidetests/jvmti/attaching/app/Android.mk
index 88727c2..59cb61b 100644
--- a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk
+++ b/hostsidetests/jvmti/attaching/app/Android.mk
@@ -20,14 +20,15 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
-LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiattachagent
 LOCAL_MULTILIB := both
 LOCAL_SDK_VERSION := current
 
 # TODO: Refactor. This is the only thing every changing.
-LOCAL_PACKAGE_NAME := CtsJvmtiRunTest981DeviceApp
+LOCAL_PACKAGE_NAME := CtsJvmtiAttachingDeviceApp
 
 include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/vm-tests-tf/AndroidManifest.xml b/hostsidetests/jvmti/attaching/app/AndroidManifest.xml
old mode 100644
new mode 100755
similarity index 60%
copy from tests/vm-tests-tf/AndroidManifest.xml
copy to hostsidetests/jvmti/attaching/app/AndroidManifest.xml
index 2a2f40a..feb7b24
--- a/tests/vm-tests-tf/AndroidManifest.xml
+++ b/hostsidetests/jvmti/attaching/app/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2007 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.
@@ -16,14 +16,11 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.core.vm-tests-tf">
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application>
-        <uses-library android:name="android.test.runner" />
+    package="android.jvmti.cts.attaching">
+
+    <application android:name="android.jvmti.JvmtiApplication" android:debuggable="true">
+        <activity android:exported="true" android:name="android.jvmti.JvmtiActivity" >
+        </activity>
     </application>
-
-    <instrumentation android:name="android.test.InstrumentationCoreTestRunner"
-                     android:targetPackage="android.core.vm-tests-tf"
-                     android:label="cts trade federation vm tests"/>
-
 </manifest>
+
diff --git a/hostsidetests/jvmti/attaching/app/jni/Android.mk b/hostsidetests/jvmti/attaching/app/jni/Android.mk
new file mode 100644
index 0000000..16f2bc1
--- /dev/null
+++ b/hostsidetests/jvmti/attaching/app/jni/Android.mk
@@ -0,0 +1,63 @@
+# 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 := libctsjvmtiattachagent
+
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := cts_agent.cpp
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+LOCAL_HEADER_LIBRARIES := libopenjdkjvmti_headers
+
+LOCAL_SHARED_LIBRARIES := liblog \
+                          libdl
+
+# The test implementation. We get this provided by ART.
+# Note: Needs to be "whole" as this exposes JNI functions.
+LOCAL_WHOLE_STATIC_LIBRARIES := libctstiagent
+
+# Platform libraries that are not available to apps. Link in statically.
+LOCAL_STATIC_LIBRARIES += libbase
+
+LOCAL_STRIP_MODULE := keep_symbols
+
+# Turn on all warnings.
+LOCAL_CFLAGS :=  -fno-rtti \
+                 -ggdb3 \
+                 -Wall \
+                 -Wextra \
+                 -Werror \
+                 -Wunreachable-code \
+                 -Wredundant-decls \
+                 -Wshadow \
+                 -Wunused \
+                 -Wimplicit-fallthrough \
+                 -Wfloat-equal \
+                 -Wint-to-void-pointer-cast \
+                 -Wused-but-marked-unused \
+                 -Wdeprecated \
+                 -Wunreachable-code-break \
+                 -Wunreachable-code-return \
+                 -g \
+                 -O0 \
+
+LOCAL_CXX_STL := libc++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/jvmti/attaching/app/jni/cts_agent.cpp b/hostsidetests/jvmti/attaching/app/jni/cts_agent.cpp
new file mode 100644
index 0000000..bb32c54
--- /dev/null
+++ b/hostsidetests/jvmti/attaching/app/jni/cts_agent.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 <jvmti.h>
+
+#include <algorithm>
+#include <mutex>
+#include <vector>
+
+#include "android-base/logging.h"
+#include "jvmti_helper.h"
+#include "scoped_utf_chars.h"
+#include "test_env.h"
+
+namespace art {
+
+static std::mutex gVectorMutex;
+static std::vector<std::string> gLoadedDescriptors;
+
+static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) {
+  char* name;
+  jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr);
+  if (result != JVMTI_ERROR_NONE) {
+    if (jni_env != nullptr) {
+      JvmtiErrorToException(jni_env, jenv, result);
+    } else {
+      printf("Failed to get class signature.\n");
+    }
+    return "";
+  }
+
+  std::string tmp(name);
+  jenv->Deallocate(reinterpret_cast<unsigned char*>(name));
+
+  return tmp;
+}
+
+static void EnableEvents(JNIEnv* env,
+                         jboolean enable,
+                         decltype(jvmtiEventCallbacks().ClassLoad) class_load,
+                         decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) {
+  if (enable == JNI_FALSE) {
+    jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                         JVMTI_EVENT_CLASS_LOAD,
+                                                         nullptr);
+    if (JvmtiErrorToException(env, jvmti_env, ret)) {
+      return;
+    }
+    ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                              JVMTI_EVENT_CLASS_PREPARE,
+                                              nullptr);
+    JvmtiErrorToException(env, jvmti_env, ret);
+    return;
+  }
+
+  jvmtiEventCallbacks callbacks;
+  memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+  callbacks.ClassLoad = class_load;
+  callbacks.ClassPrepare = class_prepare;
+  jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+  if (JvmtiErrorToException(env, jvmti_env, ret)) {
+    return;
+  }
+
+  ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                            JVMTI_EVENT_CLASS_LOAD,
+                                            nullptr);
+  if (JvmtiErrorToException(env, jvmti_env, ret)) {
+    return;
+  }
+  ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                            JVMTI_EVENT_CLASS_PREPARE,
+                                            nullptr);
+  JvmtiErrorToException(env, jvmti_env, ret);
+}
+
+static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
+                                         JNIEnv* jni_env,
+                                         jthread thread ATTRIBUTE_UNUSED,
+                                         jclass klass) {
+  std::string name = GetClassName(jenv, jni_env, klass);
+  if (name == "") {
+    return;
+  }
+  std::lock_guard<std::mutex> guard(gVectorMutex);
+  gLoadedDescriptors.push_back(name);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_android_jvmti_JvmtiActivity_didSeeLoadOf(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring descriptor) {
+  std::lock_guard<std::mutex> guard(gVectorMutex);
+  ScopedUtfChars str(env, descriptor);
+  std::string tmp = str.c_str();
+  bool found = std::find(gLoadedDescriptors.begin(), gLoadedDescriptors.end(), tmp) !=
+      gLoadedDescriptors.end();
+  return found ? JNI_TRUE : JNI_FALSE;
+}
+
+extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
+                                               char* options ATTRIBUTE_UNUSED,
+                                               void* reserved ATTRIBUTE_UNUSED) {
+  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
+    LOG(FATAL) << "Could not get shared jvmtiEnv";
+  }
+
+  SetAllCapabilities(jvmti_env);
+  return 0;
+}
+
+extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm,
+                                                 char* options ATTRIBUTE_UNUSED,
+                                                 void* reserved ATTRIBUTE_UNUSED) {
+  JNIEnv* env;
+  CHECK_EQ(0, vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6))
+      << "Could not get JNIEnv";
+
+  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
+    LOG(FATAL) << "Could not get shared jvmtiEnv";
+  }
+
+  SetAllCapabilities(jvmti_env);
+
+  EnableEvents(env, JNI_TRUE, nullptr, ClassPrepareCallback);
+
+  return 0;
+}
+
+}  // namespace art
diff --git a/hostsidetests/jvmti/attaching/app/src/android/jvmti/JvmtiActivity.java b/hostsidetests/jvmti/attaching/app/src/android/jvmti/JvmtiActivity.java
new file mode 100644
index 0000000..88a0fa9
--- /dev/null
+++ b/hostsidetests/jvmti/attaching/app/src/android/jvmti/JvmtiActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.jvmti;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import java.lang.Override;
+
+/**
+ * A specialized activity. This is separate from the other agent tests as we can't use
+ * instrumentation for this.
+ */
+public class JvmtiActivity extends Activity {
+
+    private final static String APP_DESCRIPTOR = "Landroid/jvmti/JvmtiApplication;";
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        System.out.println("Checking for " + APP_DESCRIPTOR);
+        if (!didSeeLoadOf(APP_DESCRIPTOR)) {
+            throw new IllegalStateException("Did not see the load of the application class!");
+        }
+    }
+
+    private static native boolean didSeeLoadOf(String s);
+}
diff --git a/hostsidetests/jvmti/attaching/app/src/android/jvmti/JvmtiApplication.java b/hostsidetests/jvmti/attaching/app/src/android/jvmti/JvmtiApplication.java
new file mode 100644
index 0000000..213a3f8
--- /dev/null
+++ b/hostsidetests/jvmti/attaching/app/src/android/jvmti/JvmtiApplication.java
@@ -0,0 +1,26 @@
+/*
+ * 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.jvmti;
+
+import android.app.Application;
+
+/**
+ * A specialized application. This is special compared to other agent tests as we can't use
+ * instrumentation for this and want to test early startup.
+ */
+public class JvmtiApplication extends Application {
+}
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/hostsidetests/jvmti/attaching/host/Android.mk
similarity index 65%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to hostsidetests/jvmti/attaching/host/Android.mk
index 151379b..f236fb0 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/hostsidetests/jvmti/attaching/host/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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,15 +12,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
+LOCAL_MODULE := CtsJvmtiAttachingHostTestCases
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jvmti/run-tests/test-981/AndroidTest.xml b/hostsidetests/jvmti/attaching/host/AndroidTest.xml
similarity index 76%
copy from hostsidetests/jvmti/run-tests/test-981/AndroidTest.xml
copy to hostsidetests/jvmti/attaching/host/AndroidTest.xml
index e6351d3..41c161d 100644
--- a/hostsidetests/jvmti/run-tests/test-981/AndroidTest.xml
+++ b/hostsidetests/jvmti/attaching/host/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
@@ -13,15 +13,15 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS JVMTI test cases">
+<configuration description="Config for CTS JVMTI Attaching test cases">
     <option name="config-descriptor:metadata" key="component" value="art" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsJvmtiRunTest981DeviceApp.apk" />
+        <option name="test-file-name" value="CtsJvmtiAttachingDeviceApp.apk" />
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
-        <option name="jar" value="CtsJvmtiRunTest981HostTestCases.jar" />
-        <option name="set-option" value="test-file-name:CtsJvmtiRunTest981DeviceApp.apk" />
-        <option name="set-option" value="package-name:android.jvmti.cts.run_test_981" />
+        <option name="jar" value="CtsJvmtiAttachingHostTestCases.jar" />
+        <option name="set-option" value="test-file-name:CtsJvmtiAttachingDeviceApp.apk" />
+        <option name="set-option" value="package-name:android.jvmti.cts.attaching" />
     </test>
 </configuration>
diff --git a/hostsidetests/jvmti/attaching/host/src/android/jvmti/cts/JvmtiAttachingHostTest.java b/hostsidetests/jvmti/attaching/host/src/android/jvmti/cts/JvmtiAttachingHostTest.java
new file mode 100644
index 0000000..2438f32
--- /dev/null
+++ b/hostsidetests/jvmti/attaching/host/src/android/jvmti/cts/JvmtiAttachingHostTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.jvmti.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.testrunner.ITestRunListener;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.ZipUtil;
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.ZipFile;
+
+/**
+ * Specialization of JvmtiHostTest to test attaching on startup.
+ */
+public class JvmtiAttachingHostTest extends DeviceTestCase implements IBuildReceiver, IAbiReceiver {
+    // inject these options from HostTest directly using --set-option <option name>:<option value>
+    @Option(name = "package-name",
+            description = "The package name of the device test",
+            mandatory = true)
+    private String mTestPackageName = null;
+
+    @Option(name = "test-file-name",
+            description = "the name of a test zip file to install on device.",
+            mandatory = true)
+    private String mTestApk = null;
+
+    private CompatibilityBuildHelper mBuildHelper;
+    private IAbi mAbi;
+
+    @Override
+    public void setBuild(IBuildInfo arg0) {
+        mBuildHelper = new CompatibilityBuildHelper(arg0);
+    }
+
+    @Override
+    public void setAbi(IAbi arg0) {
+        mAbi = arg0;
+    }
+
+    public void testJvmtiAttach() throws Exception {
+        final ITestDevice device = getDevice();
+
+        String testingArch = AbiUtils.getBaseArchForAbi(mAbi.getName());
+        String deviceArch = getDeviceBaseArch(device);
+
+        //Only bypass if Base Archs are different
+        if (!testingArch.equals(deviceArch)) {
+            CLog.d(
+                    "Bypass as testing Base Arch:"
+                            + testingArch
+                            + " is different from DUT Base Arch:"
+                            + deviceArch);
+            return;
+        }
+
+        if (mTestApk == null || mTestPackageName == null) {
+            throw new IllegalStateException("Incorrect configuration");
+        }
+
+        runAttachTest(device, mTestPackageName, mTestApk);
+    }
+
+    private String getDeviceBaseArch(ITestDevice device) throws Exception {
+        String abi = device.executeShellCommand("getprop ro.product.cpu.abi").replace("\n", "");
+        CLog.d("DUT abi:" + abi);
+        return AbiUtils.getBaseArchForAbi(abi);
+    }
+
+    private void runAttachTest(ITestDevice device, String pkg, String apk) {
+        try {
+            String pwd = device.executeShellCommand("run-as " + pkg + " pwd");
+            if (pwd == null) {
+                throw new RuntimeException("pwd failed");
+            }
+            pwd = pwd.trim();
+            if (pwd.isEmpty()) {
+                throw new RuntimeException("pwd failed");
+            }
+
+            String agentInDataData =
+                    installLibToDataData(device, pkg, apk, pwd, "libctsjvmtiattachagent.so");
+
+            String attachCmd = "cmd activity start -S -W --attach-agent " + agentInDataData + " -n "
+                    + pkg + "/android.jvmti.JvmtiActivity";
+
+            String attachReply = device.executeShellCommand(attachCmd);
+            // Don't try to parse the output. The test will time out anyways if this didn't
+            // work.
+            if (attachReply != null && !attachReply.trim().isEmpty()) {
+                CLog.e(attachReply);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Failed attaching", e);
+        }
+    }
+
+    String installLibToDataData(ITestDevice device, String pkg, String apk, String dataData,
+            String library) throws Exception {
+        ZipFile zf = null;
+        File tmpFile = null;
+        String libInTmp = null;
+        try {
+            String libInDataData = dataData + "/" + library;
+
+            File apkFile = mBuildHelper.getTestFile(apk);
+            zf = new ZipFile(apkFile);
+
+            String libPathInApk = "lib/" + mAbi.getName() + "/" + library;
+            tmpFile = ZipUtil.extractFileFromZip(zf, libPathInApk);
+
+            libInTmp = "/data/local/tmp/" + tmpFile.getName();
+            if (!device.pushFile(tmpFile, libInTmp)) {
+                throw new RuntimeException("Could not push library " + library + " to device");
+            }
+
+            String runAsCp = device.executeShellCommand(
+                    "run-as " + pkg + " cp " + libInTmp + " " + libInDataData);
+            if (runAsCp != null && !runAsCp.trim().isEmpty()) {
+                throw new RuntimeException(runAsCp.trim());
+            }
+
+            String runAsChmod = device
+                    .executeShellCommand("run-as " + pkg + " chmod a+x " + libInDataData);
+            if (runAsChmod != null && !runAsChmod.trim().isEmpty()) {
+                throw new RuntimeException(runAsChmod.trim());
+            }
+
+            return libInDataData;
+        } finally {
+            FileUtil.deleteFile(tmpFile);
+            ZipUtil.closeZip(zf);
+            if (libInTmp != null) {
+                try {
+                    device.executeShellCommand("rm " + libInTmp);
+                } catch (Exception e) {
+                    CLog.e("Failed cleaning up library on device");
+                }
+            }
+        }
+    }
+}
diff --git a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
index f8099ef..ce2969c 100644
--- a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
+++ b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
@@ -27,6 +27,7 @@
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.util.AbiUtils;
+import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.ZipUtil;
 import java.io.File;
 import java.util.LinkedList;
@@ -68,11 +69,6 @@
         mAbi = arg0;
     }
 
-    /**
-     * Tests the string was successfully logged to Logcat from the activity.
-     *
-     * @throws Exception
-     */
     public void testJvmti() throws Exception {
         final ITestDevice device = getDevice();
 
@@ -125,8 +121,6 @@
 
         @Override
         public void run() {
-            File tmpFile = null;
-            ZipFile zf = null;
             try {
                 String pwd = mDevice.executeShellCommand("run-as " + mPkg + " pwd");
                 if (pwd == null) {
@@ -148,23 +142,13 @@
                 }
             } catch (Exception e) {
                 throw new RuntimeException("Failed attaching", e);
-            } finally {
-                if (tmpFile != null) {
-                    tmpFile.delete();
-                }
-                if (zf != null) {
-                    try {
-                        zf.close();
-                    } catch (Exception e) {
-                        throw new RuntimeException("ZipFile close failed", e);
-                    }
-                }
             }
         }
 
         String installLibToDataData(String dataData, String library) throws Exception {
             ZipFile zf = null;
             File tmpFile = null;
+            String libInTmp = null;
             try {
                 String libInDataData = dataData + "/" + library;
 
@@ -174,7 +158,7 @@
                 String libPathInApk = "lib/" + mAbi.getName() + "/" + library;
                 tmpFile = ZipUtil.extractFileFromZip(zf, libPathInApk);
 
-                String libInTmp = "/data/local/tmp/" + tmpFile.getName();
+                libInTmp = "/data/local/tmp/" + tmpFile.getName();
                 if (!mDevice.pushFile(tmpFile, libInTmp)) {
                     throw new RuntimeException("Could not push library " + library + " to device");
                 }
@@ -193,14 +177,13 @@
 
                 return libInDataData;
             } finally {
-                if (tmpFile != null) {
-                    tmpFile.delete();
-                }
-                if (zf != null) {
+                FileUtil.deleteFile(tmpFile);
+                ZipUtil.closeZip(zf);
+                if (libInTmp != null) {
                     try {
-                        zf.close();
+                        mDevice.executeShellCommand("rm " + libInTmp);
                     } catch (Exception e) {
-                        throw new RuntimeException("ZipFile close failed", e);
+                        CLog.e("Failed cleaning up library on device");
                     }
                 }
             }
diff --git a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiPreparer.java b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiPreparer.java
deleted file mode 100644
index 1577ab3..0000000
--- a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiPreparer.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package android.jvmti.cts;
-
-import com.android.compatibility.common.tradefed.targetprep.ApkInstaller;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.config.Option;
-import com.android.tradefed.config.OptionClass;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.targetprep.TargetSetupError;
-import java.io.File;
-
-@OptionClass(alias="jvmti-installer")
-public class JvmtiPreparer extends ApkInstaller {
-    // We re-use test-file-name to find the APK. But we need to know the package name.
-    @Option(name = "package-name",
-            description = "The package name of the device test",
-            mandatory = true)
-    private String mPackageName = null;
-
-    private String storedApkName;
-
-    public final static String PACKAGE_NAME_ATTRIBUTE = "jvmti-package-name";
-    public final static String APK_ATTRIBUTE = "jvmti-apk";
-
-    @Override
-    public void setUp(ITestDevice arg0, IBuildInfo arg1)
-            throws TargetSetupError, DeviceNotAvailableException {
-        super.setUp(arg0, arg1);
-
-        arg1.addBuildAttribute(PACKAGE_NAME_ATTRIBUTE, mPackageName);
-        arg1.addBuildAttribute(APK_ATTRIBUTE, storedApkName);
-    }
-
-    @Override
-    protected File getLocalPathForFilename(IBuildInfo arg0, String arg1, ITestDevice arg2)
-            throws TargetSetupError {
-        storedApkName = arg1;
-        return super.getLocalPathForFilename(arg0, arg1, arg2);
-    }
-}
diff --git a/hostsidetests/jvmti/base/run-test-based-app/AndroidManifest.xml b/hostsidetests/jvmti/base/run-test-based-app/AndroidManifest.xml
deleted file mode 100644
index a2d6ca6..0000000
--- a/hostsidetests/jvmti/base/run-test-based-app/AndroidManifest.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?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.
- -->
-
-<!--
- * This is a sample of how to create an app for a run-test-based JVMTI
- * test.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.jvmti.cts.run_test_{NR}">
-
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-        <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="{NR}" />
-        <activity android:name="android.jvmti.JvmtiActivity" >
-        </activity>
-    </application>
-
-    <!--  self-instrumenting test package. -->
-    <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:label="CTS tests for JVMTI"
-        android:targetPackage="android.jvmti.cts.run_test_{NR}" >
-    </instrumentation>
-</manifest>
-
diff --git a/hostsidetests/jvmti/redefining/Android.mk b/hostsidetests/jvmti/redefining/Android.mk
index 4c8ac15..14297b6 100644
--- a/hostsidetests/jvmti/redefining/Android.mk
+++ b/hostsidetests/jvmti/redefining/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRedefineClassesHostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/redefining/app/Android.mk b/hostsidetests/jvmti/redefining/app/Android.mk
index 8ade23d..62e401c 100644
--- a/hostsidetests/jvmti/redefining/app/Android.mk
+++ b/hostsidetests/jvmti/redefining/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java b/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
index a7bd120..d68d1ddc 100644
--- a/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
+++ b/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
@@ -342,7 +342,6 @@
              *      return-object v0
              *  .end method
             */
-            /* DISABLED Due to b/62237378
             new RedefineError(JvmtiErrors.FAILS_VERIFICATION, Transform2.class,
                     "ZGV4CjAzNQBOhefYdQRcgqmkwhWsSyzb5I3udX0SnJ44AwAAcAAAAHhWNBIAAAAAAAAAAIwCAAAN" +
                     "AAAAcAAAAAYAAACkAAAAAQAAALwAAAAAAAAAAAAAAAMAAADIAAAAAQAAAOAAAAA4AgAAAAEAAAAB" +
@@ -359,7 +358,6 @@
                     "BgAAAKQAAAADAAAAAQAAALwAAAAFAAAAAwAAAMgAAAAGAAAAAQAAAOAAAAACIAAADQAAAAABAAAE" +
                     "IAAAAgAAABgCAAADEAAAAgAAACgCAAAGIAAAAQAAADgCAAADIAAAAgAAAEgCAAABIAAAAgAAAFQC" +
                     "AAAAIAAAAQAAAH4CAAAAEAAAAQAAAIwCAAA="),
-             */
             /**
              * Base64 for this class.
              *
diff --git a/hostsidetests/jvmti/run-tests/Android.mk b/hostsidetests/jvmti/run-tests/Android.mk
index 64fe597..d344747 100644
--- a/hostsidetests/jvmti/run-tests/Android.mk
+++ b/hostsidetests/jvmti/run-tests/Android.mk
@@ -13,5 +13,157 @@
 # limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
 
+# shim classes. We use one that exposes the common functionality.
+LOCAL_SHIM_CLASSES := \
+  src/902-hello-transformation/src/art/Redefinition.java \
+  src/903-hello-tagging/src/art/Main.java \
+  src/989-method-trace-throw/src/art/Trace.java \
+
+LOCAL_SRC_FILES := $(LOCAL_SHIM_CLASSES)
+
+# Actual test classes.
+LOCAL_SRC_FILES += \
+  src/901-hello-ti-agent/src/art/Test901.java \
+  src/902-hello-transformation/src/art/Test902.java \
+  src/903-hello-tagging/src/art/Test903.java \
+  src/904-object-allocation/src/art/Test904.java \
+  src/905-object-free/src/art/Test905.java \
+  src/906-iterate-heap/src/art/Test906.java \
+  src/907-get-loaded-classes/src/art/Test907.java \
+    src/907-get-loaded-classes/src/art/Cerr.java \
+  src/908-gc-start-finish/src/art/Test908.java \
+  src/910-methods/src/art/Test910.java \
+  src/911-get-stack-trace/src/art/Test911.java \
+    src/911-get-stack-trace/src/art/AllTraces.java \
+    src/911-get-stack-trace/src/art/ControlData.java \
+    src/911-get-stack-trace/src/art/Frames.java \
+    src/911-get-stack-trace/src/art/OtherThread.java \
+    src/911-get-stack-trace/src/art/PrintThread.java \
+    src/911-get-stack-trace/src/art/Recurse.java \
+    src/911-get-stack-trace/src/art/SameThread.java \
+    src/911-get-stack-trace/src/art/ThreadListTraces.java \
+  src/912-classes/src-art/art/Test912.java \
+    src/912-classes/src-art/art/DexData.java \
+  src/913-heaps/src/art/Test913.java \
+  src/914-hello-obsolescence/src/art/Test914.java \
+  src/915-obsolete-2/src/art/Test915.java \
+  src/917-fields-transformation/src/art/Test917.java \
+  src/918-fields/src/art/Test918.java \
+  src/919-obsolete-fields/src/art/Test919.java \
+  src/920-objects/src/art/Test920.java \
+  src/922-properties/src/art/Test922.java \
+  src/923-monitors/src/art/Test923.java \
+  src/924-threads/src/art/Test924.java \
+  src/925-threadgroups/src/art/Test925.java \
+  src/926-multi-obsolescence/src/art/Test926.java \
+  src/927-timers/src/art/Test927.java \
+  src/928-jni-table/src/art/Test928.java \
+  src/930-hello-retransform/src/art/Test930.java \
+  src/931-agent-thread/src/art/Test931.java \
+  src/932-transform-saves/src/art/Test932.java \
+  src/933-misc-events/src/art/Test933.java \
+  src/940-recursive-obsolete/src/art/Test940.java \
+  src/942-private-recursive/src/art/Test942.java \
+  src/944-transform-classloaders/src/art/Test944.java \
+  src/945-obsolete-native/src/art/Test945.java \
+  src/947-reflect-method/src/art/Test947.java \
+  src/951-threaded-obsolete/src/art/Test951.java \
+  src/982-ok-no-retransform/src/art/Test982.java \
+  src/984-obsolete-invoke/src/art/Test984.java \
+  src/985-re-obsolete/src/art/Test985.java \
+  src/986-native-method-bind/src/art/Test986.java \
+  src/988-method-trace/src/art/Test988.java \
+    src/988-method-trace/src/art/Test988Intrinsics.java \
+  src/989-method-trace-throw/src/art/Test989.java \
+  src/990-field-trace/src/art/Test990.java \
+  src/991-field-trace-2/src/art/Test991.java \
+  src/992-source-data/src/art/Test992.java \
+    src/992-source-data/src/art/Target2.java \
+
+JVMTI_RUN_TEST_GENERATED_NUMBERS := \
+  901 \
+  902 \
+  903 \
+  904 \
+  905 \
+  906 \
+  907 \
+  908 \
+  910 \
+  911 \
+  912 \
+  913 \
+  914 \
+  915 \
+  917 \
+  918 \
+  919 \
+  920 \
+  922 \
+  923 \
+  924 \
+  925 \
+  926 \
+  927 \
+  928 \
+  930 \
+  931 \
+  932 \
+  933 \
+  940 \
+  942 \
+  944 \
+  945 \
+  947 \
+  951 \
+  982 \
+  984 \
+  985 \
+  986 \
+  988 \
+  989 \
+  990 \
+  991 \
+  992 \
+
+# Try to enforce that the directories correspond to the Java files we pull in.
+JVMTI_RUN_TEST_DIR_CHECK := $(sort $(foreach DIR,$(addprefix src/,$(JVMTI_RUN_TEST_GENERATED_NUMBERS)), \
+  $(filter $(DIR)%,$(LOCAL_SRC_FILES))))
+ifneq ($(sort $(LOCAL_SRC_FILES)),$(JVMTI_RUN_TEST_DIR_CHECK))
+  $(error Missing file, compare $(sort $(LOCAL_SRC_FILES)) with $(JVMTI_RUN_TEST_DIR_CHECK))
+endif
+
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+LOCAL_MODULE := run-test-jvmti-java
+
+GENERATED_SRC_DIR := $(call local-generated-sources-dir)
+JVMTI_RUN_TEST_GENERATED_FILES := \
+  $(foreach NR,$(JVMTI_RUN_TEST_GENERATED_NUMBERS),$(GENERATED_SRC_DIR)/results.$(NR).expected.txt)
+
+define GEN_JVMTI_RUN_TEST_GENERATED_FILE
+
+GEN_INPUT := $(wildcard $(LOCAL_PATH)/src/$(1)*/expected.txt)
+GEN_OUTPUT := $(GENERATED_SRC_DIR)/results.$(1).expected.txt
+$$(GEN_OUTPUT): $$(GEN_INPUT)
+	cp $$< $$@
+
+GEN_INPUT :=
+GEN_OUTPUT :=
+
+endef
+
+$(foreach NR,$(JVMTI_RUN_TEST_GENERATED_NUMBERS),\
+  $(eval $(call GEN_JVMTI_RUN_TEST_GENERATED_FILE,$(NR))))
+LOCAL_JAVA_RESOURCE_FILES := $(JVMTI_RUN_TEST_GENERATED_FILES)
+
+# Avoid linking against any @hide APIs.
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jvmti/run-tests/src b/hostsidetests/jvmti/run-tests/src
new file mode 120000
index 0000000..0291142
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/src
@@ -0,0 +1 @@
+../../../../art/test
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-902/Android.mk b/hostsidetests/jvmti/run-tests/test-902/Android.mk
index f16dd85..1639584 100644
--- a/hostsidetests/jvmti/run-tests/test-902/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-902/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest902HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-902/app/Android.mk b/hostsidetests/jvmti/run-tests/test-902/app/Android.mk
index 7c9001b..278351b 100644
--- a/hostsidetests/jvmti/run-tests/test-902/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-902/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-903/Android.mk b/hostsidetests/jvmti/run-tests/test-903/Android.mk
index b7d15bd..f81c843 100644
--- a/hostsidetests/jvmti/run-tests/test-903/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-903/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest903HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-903/app/Android.mk b/hostsidetests/jvmti/run-tests/test-903/app/Android.mk
index c523dce..08a8f4e 100644
--- a/hostsidetests/jvmti/run-tests/test-903/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-903/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-904/Android.mk b/hostsidetests/jvmti/run-tests/test-904/Android.mk
index 3655374..73e67e8 100644
--- a/hostsidetests/jvmti/run-tests/test-904/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-904/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest904HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-904/app/Android.mk b/hostsidetests/jvmti/run-tests/test-904/app/Android.mk
index e248dab..1805c35 100644
--- a/hostsidetests/jvmti/run-tests/test-904/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-904/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-905/Android.mk b/hostsidetests/jvmti/run-tests/test-905/Android.mk
index 065585e..c5bcca1 100644
--- a/hostsidetests/jvmti/run-tests/test-905/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-905/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest905HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-905/app/Android.mk b/hostsidetests/jvmti/run-tests/test-905/app/Android.mk
index 12472e1..082dd05 100644
--- a/hostsidetests/jvmti/run-tests/test-905/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-905/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-906/Android.mk b/hostsidetests/jvmti/run-tests/test-906/Android.mk
index 5a61e0f..98005a9 100644
--- a/hostsidetests/jvmti/run-tests/test-906/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-906/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest906HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-906/app/Android.mk b/hostsidetests/jvmti/run-tests/test-906/app/Android.mk
index 783ec20..0a1b017 100644
--- a/hostsidetests/jvmti/run-tests/test-906/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-906/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-907/Android.mk b/hostsidetests/jvmti/run-tests/test-907/Android.mk
index 5629150..553f8a0 100644
--- a/hostsidetests/jvmti/run-tests/test-907/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-907/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest907HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-907/app/Android.mk b/hostsidetests/jvmti/run-tests/test-907/app/Android.mk
index 9ecfdd5..4cc8de3 100644
--- a/hostsidetests/jvmti/run-tests/test-907/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-907/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-908/Android.mk b/hostsidetests/jvmti/run-tests/test-908/Android.mk
index f260e26..ebd6ab0 100644
--- a/hostsidetests/jvmti/run-tests/test-908/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-908/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest908HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-908/app/Android.mk b/hostsidetests/jvmti/run-tests/test-908/app/Android.mk
index 8cbf7db9..f4e077c 100644
--- a/hostsidetests/jvmti/run-tests/test-908/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-908/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-910/Android.mk b/hostsidetests/jvmti/run-tests/test-910/Android.mk
index bc06790..5cf1e23 100644
--- a/hostsidetests/jvmti/run-tests/test-910/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-910/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest910HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-910/app/Android.mk b/hostsidetests/jvmti/run-tests/test-910/app/Android.mk
index acb8180..c9c903f 100644
--- a/hostsidetests/jvmti/run-tests/test-910/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-910/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-911/Android.mk b/hostsidetests/jvmti/run-tests/test-911/Android.mk
index 0906b99..009e1db 100644
--- a/hostsidetests/jvmti/run-tests/test-911/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-911/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest911HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-911/app/Android.mk b/hostsidetests/jvmti/run-tests/test-911/app/Android.mk
index d5d70d2..9441ad5 100644
--- a/hostsidetests/jvmti/run-tests/test-911/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-911/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/hostsidetests/jvmti/run-tests/test-912/Android.mk
similarity index 89%
rename from hostsidetests/jvmti/run-tests/test-981/Android.mk
rename to hostsidetests/jvmti/run-tests/test-912/Android.mk
index 151379b..7cdea77 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-912/Android.mk
@@ -16,10 +16,10 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
+LOCAL_MODULE := CtsJvmtiRunTest912HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-981/AndroidTest.xml b/hostsidetests/jvmti/run-tests/test-912/AndroidTest.xml
similarity index 87%
rename from hostsidetests/jvmti/run-tests/test-981/AndroidTest.xml
rename to hostsidetests/jvmti/run-tests/test-912/AndroidTest.xml
index e6351d3..993f9cb 100644
--- a/hostsidetests/jvmti/run-tests/test-981/AndroidTest.xml
+++ b/hostsidetests/jvmti/run-tests/test-912/AndroidTest.xml
@@ -17,11 +17,11 @@
     <option name="config-descriptor:metadata" key="component" value="art" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsJvmtiRunTest981DeviceApp.apk" />
+        <option name="test-file-name" value="CtsJvmtiRunTest912DeviceApp.apk" />
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
-        <option name="jar" value="CtsJvmtiRunTest981HostTestCases.jar" />
-        <option name="set-option" value="test-file-name:CtsJvmtiRunTest981DeviceApp.apk" />
-        <option name="set-option" value="package-name:android.jvmti.cts.run_test_981" />
+        <option name="jar" value="CtsJvmtiRunTest912HostTestCases.jar" />
+        <option name="set-option" value="test-file-name:CtsJvmtiRunTest912DeviceApp.apk" />
+        <option name="set-option" value="package-name:android.jvmti.cts.run_test_912" />
     </test>
 </configuration>
diff --git a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk b/hostsidetests/jvmti/run-tests/test-912/app/Android.mk
similarity index 91%
rename from hostsidetests/jvmti/run-tests/test-981/app/Android.mk
rename to hostsidetests/jvmti/run-tests/test-912/app/Android.mk
index 88727c2..dad7eeb 100644
--- a/hostsidetests/jvmti/run-tests/test-981/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-912/app/Android.mk
@@ -21,13 +21,13 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
 LOCAL_SDK_VERSION := current
 
 # TODO: Refactor. This is the only thing every changing.
-LOCAL_PACKAGE_NAME := CtsJvmtiRunTest981DeviceApp
+LOCAL_PACKAGE_NAME := CtsJvmtiRunTest912DeviceApp
 
 include $(BUILD_PACKAGE)
diff --git a/hostsidetests/jvmti/run-tests/test-981/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-912/app/AndroidManifest.xml
similarity index 90%
rename from hostsidetests/jvmti/run-tests/test-981/app/AndroidManifest.xml
rename to hostsidetests/jvmti/run-tests/test-912/app/AndroidManifest.xml
index a0e898a..d689692 100644
--- a/hostsidetests/jvmti/run-tests/test-981/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-912/app/AndroidManifest.xml
@@ -16,11 +16,11 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.jvmti.cts.run_test_981">
+    package="android.jvmti.cts.run_test_912">
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
-        <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="981" />
+        <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="912" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
@@ -29,7 +29,7 @@
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
         android:label="CTS tests for JVMTI"
-        android:targetPackage="android.jvmti.cts.run_test_981" >
+        android:targetPackage="android.jvmti.cts.run_test_912" >
     </instrumentation>
 </manifest>
 
diff --git a/hostsidetests/jvmti/run-tests/test-913/Android.mk b/hostsidetests/jvmti/run-tests/test-913/Android.mk
index d9cdd01..aa247f2 100644
--- a/hostsidetests/jvmti/run-tests/test-913/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-913/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest913HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-913/app/Android.mk b/hostsidetests/jvmti/run-tests/test-913/app/Android.mk
index 95b6bce..a43ad90 100644
--- a/hostsidetests/jvmti/run-tests/test-913/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-913/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-914/Android.mk b/hostsidetests/jvmti/run-tests/test-914/Android.mk
index e28f495..004b9d8 100644
--- a/hostsidetests/jvmti/run-tests/test-914/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-914/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest914HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-914/app/Android.mk b/hostsidetests/jvmti/run-tests/test-914/app/Android.mk
index 3146e3a..3b3d7bf 100644
--- a/hostsidetests/jvmti/run-tests/test-914/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-914/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-915/Android.mk b/hostsidetests/jvmti/run-tests/test-915/Android.mk
index 7934916..117a5e7 100644
--- a/hostsidetests/jvmti/run-tests/test-915/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-915/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest915HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-915/app/Android.mk b/hostsidetests/jvmti/run-tests/test-915/app/Android.mk
index 4a52e4c..ac85b08 100644
--- a/hostsidetests/jvmti/run-tests/test-915/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-915/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-917/Android.mk b/hostsidetests/jvmti/run-tests/test-917/Android.mk
index 80199f7..a1330c7 100644
--- a/hostsidetests/jvmti/run-tests/test-917/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-917/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest917HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-917/app/Android.mk b/hostsidetests/jvmti/run-tests/test-917/app/Android.mk
index 83a6d38..964fa9a 100644
--- a/hostsidetests/jvmti/run-tests/test-917/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-917/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-918/Android.mk b/hostsidetests/jvmti/run-tests/test-918/Android.mk
index 5600ece..db5134a 100644
--- a/hostsidetests/jvmti/run-tests/test-918/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-918/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest918HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-918/app/Android.mk b/hostsidetests/jvmti/run-tests/test-918/app/Android.mk
index fd9f80f..9274386 100644
--- a/hostsidetests/jvmti/run-tests/test-918/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-918/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-919/Android.mk b/hostsidetests/jvmti/run-tests/test-919/Android.mk
index 76ad7db..db1ce92 100644
--- a/hostsidetests/jvmti/run-tests/test-919/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-919/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest919HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-919/app/Android.mk b/hostsidetests/jvmti/run-tests/test-919/app/Android.mk
index f333322..230d936 100644
--- a/hostsidetests/jvmti/run-tests/test-919/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-919/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-920/Android.mk b/hostsidetests/jvmti/run-tests/test-920/Android.mk
index 678ded5..fe657c5 100644
--- a/hostsidetests/jvmti/run-tests/test-920/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-920/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest920HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-920/app/Android.mk b/hostsidetests/jvmti/run-tests/test-920/app/Android.mk
index 740c410..ee861f2 100644
--- a/hostsidetests/jvmti/run-tests/test-920/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-920/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-922/Android.mk b/hostsidetests/jvmti/run-tests/test-922/Android.mk
index aab0515..22ed7e5 100644
--- a/hostsidetests/jvmti/run-tests/test-922/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-922/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest922HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-922/app/Android.mk b/hostsidetests/jvmti/run-tests/test-922/app/Android.mk
index dc69693..70843f5 100644
--- a/hostsidetests/jvmti/run-tests/test-922/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-922/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-923/Android.mk b/hostsidetests/jvmti/run-tests/test-923/Android.mk
index 6bac152..6cd0d9a 100644
--- a/hostsidetests/jvmti/run-tests/test-923/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-923/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest923HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-923/app/Android.mk b/hostsidetests/jvmti/run-tests/test-923/app/Android.mk
index 6284f7d..b638272 100644
--- a/hostsidetests/jvmti/run-tests/test-923/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-923/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-924/Android.mk b/hostsidetests/jvmti/run-tests/test-924/Android.mk
index c16350b..d82624d 100644
--- a/hostsidetests/jvmti/run-tests/test-924/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-924/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest924HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-924/app/Android.mk b/hostsidetests/jvmti/run-tests/test-924/app/Android.mk
index 18e4f72..7136929 100644
--- a/hostsidetests/jvmti/run-tests/test-924/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-924/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-926/Android.mk b/hostsidetests/jvmti/run-tests/test-926/Android.mk
index 3ea1d85..ecc0adf 100644
--- a/hostsidetests/jvmti/run-tests/test-926/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-926/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest926HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-926/app/Android.mk b/hostsidetests/jvmti/run-tests/test-926/app/Android.mk
index 3436029..3d531ff 100644
--- a/hostsidetests/jvmti/run-tests/test-926/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-926/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-927/Android.mk b/hostsidetests/jvmti/run-tests/test-927/Android.mk
index 98d5f2e..c21e1b3 100644
--- a/hostsidetests/jvmti/run-tests/test-927/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-927/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest927HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-927/app/Android.mk b/hostsidetests/jvmti/run-tests/test-927/app/Android.mk
index 1e8fdb3..0443b1b 100644
--- a/hostsidetests/jvmti/run-tests/test-927/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-927/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-928/Android.mk b/hostsidetests/jvmti/run-tests/test-928/Android.mk
index 6084806..a39c00c 100644
--- a/hostsidetests/jvmti/run-tests/test-928/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-928/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest928HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-928/app/Android.mk b/hostsidetests/jvmti/run-tests/test-928/app/Android.mk
index fa3537f..75ba90c 100644
--- a/hostsidetests/jvmti/run-tests/test-928/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-928/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-930/Android.mk b/hostsidetests/jvmti/run-tests/test-930/Android.mk
index 10a3d18..c167010 100644
--- a/hostsidetests/jvmti/run-tests/test-930/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-930/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest930HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-930/app/Android.mk b/hostsidetests/jvmti/run-tests/test-930/app/Android.mk
index 6affa06..8a35455 100644
--- a/hostsidetests/jvmti/run-tests/test-930/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-930/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-931/Android.mk b/hostsidetests/jvmti/run-tests/test-931/Android.mk
index 063c6f5..efaf177 100644
--- a/hostsidetests/jvmti/run-tests/test-931/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-931/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest931HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-931/app/Android.mk b/hostsidetests/jvmti/run-tests/test-931/app/Android.mk
index 52eed76..c1be435dc 100644
--- a/hostsidetests/jvmti/run-tests/test-931/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-931/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-932/Android.mk b/hostsidetests/jvmti/run-tests/test-932/Android.mk
index 198adae..87f3f50 100644
--- a/hostsidetests/jvmti/run-tests/test-932/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-932/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest932HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-932/app/Android.mk b/hostsidetests/jvmti/run-tests/test-932/app/Android.mk
index e0c96d3..970365b 100644
--- a/hostsidetests/jvmti/run-tests/test-932/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-932/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-940/Android.mk b/hostsidetests/jvmti/run-tests/test-940/Android.mk
index 453dee0..a45027b 100644
--- a/hostsidetests/jvmti/run-tests/test-940/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-940/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest940HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-940/app/Android.mk b/hostsidetests/jvmti/run-tests/test-940/app/Android.mk
index 0ba569c..bc0476f 100644
--- a/hostsidetests/jvmti/run-tests/test-940/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-940/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-942/Android.mk b/hostsidetests/jvmti/run-tests/test-942/Android.mk
index 8a6657f..cca98d1 100644
--- a/hostsidetests/jvmti/run-tests/test-942/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-942/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest942HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-942/app/Android.mk b/hostsidetests/jvmti/run-tests/test-942/app/Android.mk
index a29d4b6..5b077b4 100644
--- a/hostsidetests/jvmti/run-tests/test-942/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-942/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-944/Android.mk b/hostsidetests/jvmti/run-tests/test-944/Android.mk
index b90c3e3..a824d42 100644
--- a/hostsidetests/jvmti/run-tests/test-944/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-944/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest944HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-944/app/Android.mk b/hostsidetests/jvmti/run-tests/test-944/app/Android.mk
index d564fc5..197b5fe 100644
--- a/hostsidetests/jvmti/run-tests/test-944/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-944/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-945/Android.mk b/hostsidetests/jvmti/run-tests/test-945/Android.mk
index 754d7ca..d236d62 100644
--- a/hostsidetests/jvmti/run-tests/test-945/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-945/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest945HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-945/app/Android.mk b/hostsidetests/jvmti/run-tests/test-945/app/Android.mk
index b1a8290..5326258 100644
--- a/hostsidetests/jvmti/run-tests/test-945/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-945/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-947/Android.mk b/hostsidetests/jvmti/run-tests/test-947/Android.mk
index 6a612e2..bdcabac 100644
--- a/hostsidetests/jvmti/run-tests/test-947/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-947/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest947HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-947/app/Android.mk b/hostsidetests/jvmti/run-tests/test-947/app/Android.mk
index 5d315e8..7f807d0 100644
--- a/hostsidetests/jvmti/run-tests/test-947/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-947/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-951/Android.mk b/hostsidetests/jvmti/run-tests/test-951/Android.mk
index 5a6d494..e15f415 100644
--- a/hostsidetests/jvmti/run-tests/test-951/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-951/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest951HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-951/app/Android.mk b/hostsidetests/jvmti/run-tests/test-951/app/Android.mk
index 273bec3..f70496c 100644
--- a/hostsidetests/jvmti/run-tests/test-951/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-951/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-982/Android.mk b/hostsidetests/jvmti/run-tests/test-982/Android.mk
index 154bc70..458c5fe 100644
--- a/hostsidetests/jvmti/run-tests/test-982/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-982/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest982HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-982/app/Android.mk b/hostsidetests/jvmti/run-tests/test-982/app/Android.mk
index c6099b3..3b32dfe 100644
--- a/hostsidetests/jvmti/run-tests/test-982/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-982/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-984/Android.mk b/hostsidetests/jvmti/run-tests/test-984/Android.mk
index 1ff5f2e..bf2f3e0 100644
--- a/hostsidetests/jvmti/run-tests/test-984/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-984/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest984HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-984/app/Android.mk b/hostsidetests/jvmti/run-tests/test-984/app/Android.mk
index 0a3c5ef..dad792a 100644
--- a/hostsidetests/jvmti/run-tests/test-984/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-984/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-985/Android.mk b/hostsidetests/jvmti/run-tests/test-985/Android.mk
index 0ed12de..1f9d2a4 100644
--- a/hostsidetests/jvmti/run-tests/test-985/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-985/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest985HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-985/app/Android.mk b/hostsidetests/jvmti/run-tests/test-985/app/Android.mk
index e092712..3a66405 100644
--- a/hostsidetests/jvmti/run-tests/test-985/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-985/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/run-tests/test-986/Android.mk b/hostsidetests/jvmti/run-tests/test-986/Android.mk
index 8e6ec6f..3d8bf7c 100644
--- a/hostsidetests/jvmti/run-tests/test-986/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-986/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiRunTest986HostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/run-tests/test-986/app/Android.mk b/hostsidetests/jvmti/run-tests/test-986/app/Android.mk
index 6914162..7e907c3 100644
--- a/hostsidetests/jvmti/run-tests/test-986/app/Android.mk
+++ b/hostsidetests/jvmti/run-tests/test-986/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES :=
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/jvmti/tagging/Android.mk b/hostsidetests/jvmti/tagging/Android.mk
index b5674cb..0351f04 100644
--- a/hostsidetests/jvmti/tagging/Android.mk
+++ b/hostsidetests/jvmti/tagging/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := CtsJvmtiTaggingHostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
 LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/jvmti/tagging/app/Android.mk b/hostsidetests/jvmti/tagging/app/Android.mk
index 3cd89c1..bd4faf1 100644
--- a/hostsidetests/jvmti/tagging/app/Android.mk
+++ b/hostsidetests/jvmti/tagging/app/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceAppBase
 LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
 LOCAL_MULTILIB := both
diff --git a/hostsidetests/media/Android.mk b/hostsidetests/media/Android.mk
index 36e9066..db83686 100644
--- a/hostsidetests/media/Android.mk
+++ b/hostsidetests/media/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsMediaHostTestCases
 
diff --git a/hostsidetests/media/app/MediaSessionTest/Android.mk b/hostsidetests/media/app/MediaSessionTest/Android.mk
index eb9059d..fb0fe40 100644
--- a/hostsidetests/media/app/MediaSessionTest/Android.mk
+++ b/hostsidetests/media/app/MediaSessionTest/Android.mk
@@ -16,7 +16,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsMediaSessionHostTestApp
 
diff --git a/hostsidetests/media/app/MediaSessionTestHelper/Android.mk b/hostsidetests/media/app/MediaSessionTestHelper/Android.mk
index 3944cb6..871140a 100644
--- a/hostsidetests/media/app/MediaSessionTestHelper/Android.mk
+++ b/hostsidetests/media/app/MediaSessionTestHelper/Android.mk
@@ -30,7 +30,7 @@
     $(call all-java-files-under, ../../common)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsMediaSessionTestHelper
 
diff --git a/hostsidetests/media/app/MediaSessionTestHelper/src/android/media/app/media_session_test_helper/MediaSessionTestHelperService.java b/hostsidetests/media/app/MediaSessionTestHelper/src/android/media/app/media_session_test_helper/MediaSessionTestHelperService.java
index a161ba5..2460672 100644
--- a/hostsidetests/media/app/MediaSessionTestHelper/src/android/media/app/media_session_test_helper/MediaSessionTestHelperService.java
+++ b/hostsidetests/media/app/MediaSessionTestHelper/src/android/media/app/media_session_test_helper/MediaSessionTestHelperService.java
@@ -17,6 +17,8 @@
 package android.media.app.media_session_test_helper;
 
 import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.app.Service;
 import android.content.Intent;
 import android.media.session.MediaSession;
@@ -41,6 +43,7 @@
     private static final String TAG = "MediaSessionTestHelperService";
 
     private static final int NOTIFICATION_ID = 100;
+    private static final String NOTIFICATION_CHANNEL = TAG;
 
     private MediaSession mMediaSession;
 
@@ -49,7 +52,13 @@
         super.onCreate();
 
         // Build notification UI to make this a foreground service.
-        Notification notification = new Notification.Builder(this)
+        NotificationManager manager =
+                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL,
+                getString(R.string.label), NotificationManager.IMPORTANCE_DEFAULT);
+        manager.createNotificationChannel(notificationChannel);
+
+        Notification notification = new Notification.Builder(this, NOTIFICATION_CHANNEL)
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
                 .setContentTitle(getString(R.string.label)).build();
         startForeground(NOTIFICATION_ID, notification);
diff --git a/hostsidetests/media/bitstreams/Android.mk b/hostsidetests/media/bitstreams/Android.mk
index 6a0cafe..2133f39 100644
--- a/hostsidetests/media/bitstreams/Android.mk
+++ b/hostsidetests/media/bitstreams/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_MODULE := CtsMediaBitstreamsTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/media/bitstreams/app/Android.mk b/hostsidetests/media/bitstreams/app/Android.mk
index df8e6a4..6070146 100644
--- a/hostsidetests/media/bitstreams/app/Android.mk
+++ b/hostsidetests/media/bitstreams/app/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util media-bitstreams-common-devicesidelib
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsMediaBitstreamsDeviceSideTestApp
 
diff --git a/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java b/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
index 92f0d2a..32fc86b 100644
--- a/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
+++ b/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
@@ -21,6 +21,7 @@
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.media.cts.bitstreams.MediaBitstreams;
@@ -161,12 +162,18 @@
                 }
 
                 MediaFormat format = parseTrackFormat(formatStr);
-                if (!MediaUtils.checkDecoderForFormat(format)) {
-                    continue;
-                }
+                String mime = format.getString(MediaFormat.KEY_MIME);
+                String[] decoders = MediaUtils.getDecoderNamesForMime(mime);
 
                 ps.println(path);
+                ps.println(decoders.length);
+                for (String name : decoders) {
+                    ps.println(name);
+                    ps.println(MediaUtils.supports(name, format));
+                }
+
             }
+
             ps.flush();
         }
     }
diff --git a/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java b/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java
index 8b9a507..b4ab76c 100644
--- a/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java
+++ b/hostsidetests/media/bitstreams/common/src/android/media/cts/bitstreams/MediaBitstreams.java
@@ -38,17 +38,21 @@
     public static final String DEFAULT_DEVICE_BITSTEAMS_PATH = "/data/local/tmp/TestVectorsIttiam";
 
     /* metric keys */
-    public static final String KEY_BITSTREAMS_FORMATS_XML = "bitstreams-formats-xml";
-    public static final String KEY_SUPPORTED_BITSTREAMS_TXT = "supported-bitstreams-txt";
-    public static final String KEY_BITSTREAMS_VALIDATION_TXT = "bitstreams-validation-txt";
-    public static final String KEY_APP_CACHE_DIR = "app-cache-dir";
-    public static final String KEY_ERR_MSG = "err-msg";
+    public static final String KEY_BITSTREAMS_FORMATS_XML = "bitstreams_formats_xml";
+    public static final String KEY_SUPPORTED_BITSTREAMS_TXT = "supported_bitstreams_txt";
+    public static final String KEY_BITSTREAMS_VALIDATION_TXT = "bitstreams_validation_txt";
+    public static final String KEY_APP_CACHE_DIR = "app_cache_dir";
+    public static final String KEY_ERR_MSG = "err_msg";
+    public static final String KEY_PATH = "path";
+    public static final String KEY_CODEC_NAME = "codec_name";
+    public static final String KEY_STATUS = "status";
 
     /* constants */
     public static final String K_MODULE = "CtsMediaBitstreamsTestCases";
     public static final String K_BITSTREAMS_LIST_TXT = "bitstreamsFile.txt";
     public static final String K_TEST_GET_SUPPORTED_BITSTREAMS = "testGetSupportedBitstreams";
     public static final String K_NATIVE_CRASH = "native crash";
+    public static final String K_UNSUPPORTED = "unsupported";
 
     public static final String DYNAMIC_CONFIG_XML = "DynamicConfig.xml";
     public static final String DYNAMIC_CONFIG = "dynamicConfig";
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java
index 9d08606..0da0193 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/MediaBitstreamsTest.java
@@ -46,6 +46,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -168,6 +169,29 @@
         return Thread.currentThread().getStackTrace()[2].getMethodName();
     }
 
+    private MetricsReportLog createReport(String methodName) {
+        String className = MediaBitstreamsTest.class.getCanonicalName();
+        MetricsReportLog report = new MetricsReportLog(
+                mBuildHelper.getBuildInfo(), mAbi.getName(),
+                String.format("%s#%s", className, methodName),
+                MediaBitstreams.K_MODULE, "media_bitstreams_conformance");
+        return report;
+    }
+
+    /**
+     * @param method test method name in the form class#method
+     * @param p path to bitstream
+     * @param d decoder name
+     * @param s test status: unsupported, true, false, crash, or timeout.
+     */
+    private void addConformanceEntry(String method, String p, String d, String s) {
+        MetricsReportLog report = createReport(method);
+        report.addValue(MediaBitstreams.KEY_PATH, p, ResultType.NEUTRAL, ResultUnit.NONE);
+        report.addValue(MediaBitstreams.KEY_CODEC_NAME, d, ResultType.NEUTRAL, ResultUnit.NONE);
+        report.addValue(MediaBitstreams.KEY_STATUS, s, ResultType.NEUTRAL, ResultUnit.NONE);
+        report.submit();
+    }
+
     Map<String, String> getArgs() {
         Map<String, String> args = new HashMap<>();
         args.put(MediaBitstreams.OPT_DEBUG_TARGET_DEVICE, Boolean.toString(mDebugTargetDevice));
@@ -274,14 +298,9 @@
 
                 String path = lines[i++];
                 mProcessedBitstreams.add(path);
-                String className = MediaBitstreamsTest.class.getCanonicalName();
-                MetricsReportLog report = new MetricsReportLog(
-                        mBuildHelper.getBuildInfo(), mAbi.getName(),
-                        String.format("%s#%s", className, mMethodName),
-                        getClass().getSimpleName(), path.replaceAll("[./]", "_"));
+                String errMsg;
 
                 boolean failedEarly;
-                String errMsg;
                 if (i < lines.length) {
                     failedEarly = Boolean.parseBoolean(lines[i++]);
                     errMsg = failedEarly ? lines[i++] : "";
@@ -291,27 +310,26 @@
                     mLastCrash = MediaBitstreams.generateCrashSignature(path, "");
                     mProcessedBitstreams.removeLast();
                 }
+
                 if (failedEarly) {
-                    String keyErrMsg = MediaBitstreams.KEY_ERR_MSG;
-                    report.addValue(keyErrMsg, errMsg, ResultType.NEUTRAL, ResultUnit.NONE);
-                    report.submit();
+                    addConformanceEntry(mMethodName, path, null, errMsg);
                     continue;
                 }
 
                 int n = Integer.parseInt(lines[i++]);
                 for (int j = 0; j < n && i < lines.length; j++) {
-                    String name = lines[i++];
+                    String decoderName = lines[i++];
                     String result;
                     if (i < lines.length) {
                         result = lines[i++];
                     } else {
                         result = MediaBitstreams.K_NATIVE_CRASH;
-                        mLastCrash = MediaBitstreams.generateCrashSignature(path, name);
+                        mLastCrash = MediaBitstreams.generateCrashSignature(path, decoderName);
                         mProcessedBitstreams.removeLast();
                     }
-                    report.addValue(name, result, ResultType.NEUTRAL, ResultUnit.NONE);
+                    addConformanceEntry(mMethodName, path, decoderName, result);
                 }
-                report.submit();
+
 
             }
         }
@@ -345,8 +363,8 @@
         ReportProcessor processor = new ProcessBitstreamsFormats();
         processor.processDeviceReport(
                 getDevice(),
-                mBuildHelper.getTestsDir(),
-                getCurrentMethod(), MediaBitstreams.KEY_BITSTREAMS_FORMATS_XML);
+                getCurrentMethod(),
+                MediaBitstreams.KEY_BITSTREAMS_FORMATS_XML);
     }
 
     @Test
@@ -363,9 +381,9 @@
         preparer = new SupportedBitstreamsProcessor(prefix, mDebugTargetDevice);
         preparer.processDeviceReport(
                 device,
-                mBuildHelper.getTestsDir(),
                 MediaBitstreams.K_TEST_GET_SUPPORTED_BITSTREAMS,
                 MediaBitstreams.KEY_SUPPORTED_BITSTREAMS_TXT);
+        Set<String> bitstreams = preparer.getBitstreams();
         Set<String> supportedBitstreams = preparer.getSupportedBitstreams();
         CLog.i("%d supported bitstreams under %s", supportedBitstreams.size(), prefix);
 
@@ -373,35 +391,43 @@
         long size = 0;
         long limit = device.getExternalStoreFreeSpace() * mUtilizationRate * 1024 / 100;
 
-        String currentMethod = getCurrentMethod();
-        Set<String> bitstreams = new LinkedHashSet<>();
-        Iterator<String> iter = supportedBitstreams.iterator();
+        String curMethod = getCurrentMethod();
+        Set<String> toPush = new LinkedHashSet<>();
+        Iterator<String> iter = bitstreams.iterator();
 
-        for (int i = 0; i < supportedBitstreams.size(); i++) {
+        for (int i = 0; i < bitstreams.size(); i++) {
 
             if (n >= mNumBatches) {
                 break;
             }
 
-            String bitstreamPath = iter.next();
-            File bitstreamFile = new File(mHostBitstreamsPath, bitstreamPath);
-            String md5Path = MediaBitstreams.getMd5Path(bitstreamPath);
-            File md5File = new File(mHostBitstreamsPath, md5Path);
-
-            if (md5File.exists() && bitstreamFile.exists()) {
-                size += md5File.length();
-                size += bitstreamFile.length();
-                bitstreams.add(bitstreamPath);
+            String p = iter.next();
+            Map<String, Boolean> decoderCapabilities;
+            decoderCapabilities = preparer.getDecoderCapabilitiesForPath(p);
+            for (Entry<String, Boolean> entry : decoderCapabilities.entrySet()) {
+                Boolean supported = entry.getValue();
+                if (supported) {
+                    File bitstreamFile = new File(mHostBitstreamsPath, p);
+                    String md5Path = MediaBitstreams.getMd5Path(p);
+                    File md5File = new File(mHostBitstreamsPath, md5Path);
+                    if (md5File.exists() && bitstreamFile.exists() && toPush.add(p)) {
+                        size += md5File.length();
+                        size += bitstreamFile.length();
+                    }
+                } else {
+                    String d = entry.getKey();
+                    addConformanceEntry(curMethod, p, d, MediaBitstreams.K_UNSUPPORTED);
+                }
             }
 
-            if (size > limit || i + 1 == supportedBitstreams.size()) {
+            if (size > limit || i + 1 == bitstreams.size()) {
                 ReportProcessor processor;
-                processor = new ProcessBitstreamsValidation(bitstreams, currentMethod);
+                processor = new ProcessBitstreamsValidation(toPush, curMethod);
                 processor.processDeviceReport(
                         device,
-                        mBuildHelper.getTestsDir(),
-                        currentMethod, MediaBitstreams.KEY_BITSTREAMS_VALIDATION_TXT);
-                bitstreams.clear();
+                        curMethod,
+                        MediaBitstreams.KEY_BITSTREAMS_VALIDATION_TXT);
+                toPush.clear();
                 size = 0;
                 n++;
             }
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 8c41347..bb3daa7 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
@@ -22,7 +22,6 @@
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.testtype.AndroidJUnitTest;
-import java.io.File;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
@@ -39,7 +38,6 @@
     private final Map<String, String> mMetrics = new HashMap<>();
     private String mFailureStackTrace = null;
 
-    private static final String APP_APK = "CtsMediaBitstreamsDeviceSideTestApp.apk";
     private static final String APP_CLS_NAME = "MediaBitstreamsDeviceSideTest";
     private static final String APP_PKG_NAME = "android.media.cts.bitstreams.app";
 
@@ -123,13 +121,10 @@
     }
 
     private boolean runDeviceTest(
-            ITestDevice device, File testDir, String method, String reportKey,
-            int testTimeout, long shellTimeout)
+            ITestDevice device, String method, String reportKey, int testTimeout,
+            long shellTimeout)
             throws DeviceNotAvailableException {
 
-        File apkFile = new File(testDir, APP_APK);
-        device.installPackage(apkFile, true, true);
-
         String fullTestName = String.format("%s.%s#%s", APP_PKG_NAME, APP_CLS_NAME, method);
         AndroidJUnitTest instrTest = new AndroidJUnitTest();
         instrTest.setDevice(device);
@@ -159,11 +154,11 @@
     }
 
     void processDeviceReport(
-            ITestDevice device, File testDir, String method, String reportKey)
+            ITestDevice device, String method, String reportKey)
             throws DeviceNotAvailableException, IOException {
         try {
             setUp(device);
-            while (!runDeviceTest(device, testDir, method, reportKey, 0, 0)) {
+            while (!runDeviceTest(device, method, reportKey, 0, 0)) {
                 if (!recover(device, mMetrics.get(reportKey))) {
                     return;
                 }
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/SupportedBitstreamsProcessor.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/SupportedBitstreamsProcessor.java
index 8a6c74e..87ccda4 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/SupportedBitstreamsProcessor.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/SupportedBitstreamsProcessor.java
@@ -18,6 +18,8 @@
 
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -32,13 +34,14 @@
     private final String mPrefix;
     private final boolean mDebugTargetDevice;
     private final Set<String> mSupportedBitstreams = new LinkedHashSet<>();
+    private final Map<String, Map<String, Boolean>> mDecodersForPath = new HashMap<>();
 
     public SupportedBitstreamsProcessor() {
         this("",false);
     }
 
     /**
-     * @param prefix only bitstreams whose relative path starts with {@code prefix}
+     * @param prefix only bitstreams whose relative paths start with {@code prefix}
      * would be processed
      * @param debugTargetDevice whether to pause {@code device} for debugging
      */
@@ -48,12 +51,26 @@
     }
 
     /**
-     * @return paths of supported devices on device
+     * @return paths to bitstreams that are supported on device
      */
     public Set<String> getSupportedBitstreams() {
         return mSupportedBitstreams;
     }
 
+    /**
+     * @return paths to all bitstreams whose relative paths start with <code>prefix</code>
+     */
+    public Set<String> getBitstreams() {
+        return mDecodersForPath.keySet();
+    }
+
+    public Map<String, Boolean> getDecoderCapabilitiesForPath(String path) {
+        if (mDecodersForPath.containsKey(path)) {
+            return mDecodersForPath.get(path);
+        }
+        return Collections.emptyMap();
+    }
+
     @Override
     Map<String, String> getArgs() {
         Map<String, String> args = new HashMap<>();
@@ -65,11 +82,29 @@
     @Override
     void process(ITestDevice device, String reportPath) throws DeviceNotAvailableException {
         mSupportedBitstreams.clear();
-        for (String path: getReportLines(device, reportPath)) {
-            if (path.isEmpty()) {
-                continue;
+        String[] lines = getReportLines(device, reportPath);
+        try {
+            for (int i = 0; i < lines.length;) {
+                String path = lines[i++];
+                int n = Integer.parseInt(lines[i++]);
+                for (int j = 0; j < n; j++) {
+                    String name = lines[i++];
+                    String status = lines[i++];
+                    boolean supported = status.equals("true");
+                    if (supported) {
+                        mSupportedBitstreams.add(path);
+                    }
+                    Map<String, Boolean> decoderCapabilities;
+                    if (mDecodersForPath.containsKey(path)) {
+                        decoderCapabilities = mDecodersForPath.get(path);
+                    } else {
+                        mDecodersForPath.put(path, decoderCapabilities = new HashMap<>());
+                    }
+                    decoderCapabilities.put(name, supported);
+                }
             }
-            mSupportedBitstreams.add(path);
+        } catch (Exception e) {
+            CLog.w(e);
         }
     }
 
diff --git a/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java b/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java
index 7e52737..3e44c4f 100644
--- a/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java
+++ b/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java
@@ -17,7 +17,6 @@
 package android.media.cts;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -85,64 +84,57 @@
     private Set<String> mExistingPackages;
     private List<Integer> mExistingUsers;
     private HashSet<String> mAvailableFeatures;
-    protected boolean mHasManagedUsersFeature;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         // Ensure that build has been set before test is run.
         assertNotNull(mCtsBuild);
-        mHasManagedUsersFeature = hasDeviceFeature("android.software.managed_users");
+        mExistingPackages = getDevice().getInstalledPackageNames();
 
-        if (mHasManagedUsersFeature) {
-            mExistingPackages = getDevice().getInstalledPackageNames();
+        // Disable the package verifier to avoid the dialog when installing an app
+        mPackageVerifier =
+                getSettings(
+                        SETTINGS_PACKAGE_VERIFIER_NAMESPACE,
+                        SETTINGS_PACKAGE_VERIFIER_NAME,
+                        USER_ALL);
+        putSettings(
+                SETTINGS_PACKAGE_VERIFIER_NAMESPACE,
+                SETTINGS_PACKAGE_VERIFIER_NAME,
+                "0",
+                USER_ALL);
 
-            // Disable the package verifier to avoid the dialog when installing an app
-            mPackageVerifier =
-                    getSettings(
-                            SETTINGS_PACKAGE_VERIFIER_NAMESPACE,
-                            SETTINGS_PACKAGE_VERIFIER_NAME,
-                            USER_ALL);
-            putSettings(
-                    SETTINGS_PACKAGE_VERIFIER_NAMESPACE,
-                    SETTINGS_PACKAGE_VERIFIER_NAME,
-                    "0",
-                    USER_ALL);
+        mExistingUsers = new ArrayList();
+        int primaryUserId = getDevice().getPrimaryUserId();
+        mExistingUsers.add(primaryUserId);
+        mExistingUsers.add(USER_SYSTEM);
 
-            mExistingUsers = new ArrayList();
-            int primaryUserId = getDevice().getPrimaryUserId();
-            mExistingUsers.add(primaryUserId);
-            mExistingUsers.add(USER_SYSTEM);
-
-            executeShellCommand("am switch-user " + primaryUserId);
-            executeShellCommand("wm dismiss-keyguard");
-        }
+        executeShellCommand("am switch-user " + primaryUserId);
+        executeShellCommand("wm dismiss-keyguard");
     }
 
     @Override
     protected void tearDown() throws Exception {
-        if (mHasManagedUsersFeature) {
-            // Reset the package verifier setting to its original value.
-            putSettings(
-                    SETTINGS_PACKAGE_VERIFIER_NAMESPACE,
-                    SETTINGS_PACKAGE_VERIFIER_NAME,
-                    mPackageVerifier,
-                    USER_ALL);
+        // Reset the package verifier setting to its original value.
+        putSettings(
+                SETTINGS_PACKAGE_VERIFIER_NAMESPACE,
+                SETTINGS_PACKAGE_VERIFIER_NAME,
+                mPackageVerifier,
+                USER_ALL);
 
-            // Remove users created during the test.
-            for (int userId : getDevice().listUsers()) {
-                if (!mExistingUsers.contains(userId)) {
-                    removeUser(userId);
-                }
+        // Remove users created during the test.
+        for (int userId : getDevice().listUsers()) {
+            if (!mExistingUsers.contains(userId)) {
+                removeUser(userId);
             }
-            // Remove packages installed during the test.
-            for (String packageName : getDevice().getUninstallablePackageNames()) {
-                if (mExistingPackages.contains(packageName)) {
-                    continue;
-                }
-                CLog.d("Removing leftover package: " + packageName);
-                getDevice().uninstallPackage(packageName);
+        }
+        // Remove packages installed during the test.
+        for (String packageName : getDevice().getUninstallablePackageNames()) {
+            if (mExistingPackages.contains(packageName)) {
+                continue;
             }
+            CLog.d("Removing leftover package: " + packageName);
+            getDevice().uninstallPackage(packageName);
         }
         super.tearDown();
     }
@@ -368,13 +360,6 @@
             }
         }
         boolean result = mAvailableFeatures.contains(requiredFeature);
-        if (!result) {
-            CLog.logAndDisplay(
-                    LogLevel.INFO,
-                    "Device doesn't have required feature "
-                            + requiredFeature
-                            + ". Test won't run.");
-        }
         return result;
     }
 }
diff --git a/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java b/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
index 1067a85..da5b354 100644
--- a/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
+++ b/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
@@ -26,6 +26,7 @@
 
 import android.platform.test.annotations.RequiresDevice;
 
+import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 
@@ -66,14 +67,13 @@
     public void setUp() throws Exception {
         super.setUp();
         mNotificationListeners = new HashMap<>();
+
+        // Ensure that the previously running media session test helper app doesn't exist.
+        getDevice().uninstallPackage(MEDIA_SESSION_TEST_HELPER_PKG);
     }
 
     @Override
     public void tearDown() throws Exception {
-        if (!mHasManagedUsersFeature) {
-            return;
-        }
-
         // Cleanup
         for (int userId : mNotificationListeners.keySet()) {
             String notificationListener = mNotificationListeners.get(userId);
@@ -84,17 +84,10 @@
     }
 
     /**
-     * Tests {@link MediaSessionManager#getActiveSessions} with the multi-users environment.
+     * Tests {@link MediaSessionManager#getActiveSessions} with the primary user.
      */
     @RequiresDevice
-    public void testGetActiveSessions() throws Exception {
-        if (!mHasManagedUsersFeature) {
-            return;
-        }
-
-        // Ensure that the previously running media session test helper app doesn't exist.
-        getDevice().uninstallPackage(MEDIA_SESSION_TEST_HELPER_PKG);
-
+    public void testGetActiveSessions_primaryUser() throws Exception {
         int primaryUserId = getDevice().getPrimaryUserId();
 
         allowGetActiveSessionForTest(primaryUserId);
@@ -107,9 +100,16 @@
 
         sendControlCommand(primaryUserId, FLAG_SET_MEDIA_SESSION_ACTIVE);
         runTest("testGetActiveSessions_hasMediaSessionFromMediaSessionTestHelper");
+    }
 
+    /**
+     * Tests {@link MediaSessionManager#getActiveSessions} with additional users.
+     */
+    @RequiresDevice
+    public void testGetActiveSessions_additionalUser() throws Exception {
         if (!canCreateAdditionalUsers(1)) {
-            CLog.w("Cannot create a new user. Skipping multi-user test cases.");
+            CLog.logAndDisplay(LogLevel.INFO,
+                    "Cannot create a new user. Skipping multi-user test cases.");
             return;
         }
 
@@ -119,18 +119,42 @@
         allowGetActiveSessionForTest(newUser);
         runTestAsUser("testGetActiveSessions_noMediaSession", newUser);
         removeUser(newUser);
+    }
 
-        // Test if another managed profile can get the session.
+    /**
+     * Tests {@link MediaSessionManager#getActiveSessions} with restricted profiles.
+     */
+    @RequiresDevice
+    public void testGetActiveSessions_restrictedProfiles() throws Exception {
+        if (!canCreateAdditionalUsers(1)) {
+            CLog.logAndDisplay(LogLevel.INFO,
+                    "Cannot create a new user. Skipping multi-user test cases.");
+            return;
+        }
+
+        // Test if another restricted profile can get the session.
         // Remove the created user first not to exceed system's user number limit.
-        newUser = createAndStartManagedProfile(primaryUserId);
+        int newUser = createAndStartRestrictedProfile(getDevice().getPrimaryUserId());
         installAppAsUser(DEVICE_SIDE_TEST_APK, newUser);
         allowGetActiveSessionForTest(newUser);
         runTestAsUser("testGetActiveSessions_noMediaSession", newUser);
         removeUser(newUser);
+    }
 
-        // Test if another restricted profile can get the session.
+    /**
+     * Tests {@link MediaSessionManager#getActiveSessions} with managed profiles.
+     */
+    @RequiresDevice
+    public void testGetActiveSessions_managedProfiles() throws Exception {
+        if (!hasDeviceFeature("android.software.managed_users")) {
+            CLog.logAndDisplay(LogLevel.INFO,
+                    "Device doesn't support managed profiles. Test won't run.");
+            return;
+        }
+
+        // Test if another managed profile can get the session.
         // Remove the created user first not to exceed system's user number limit.
-        newUser = createAndStartRestrictedProfile(primaryUserId);
+        int newUser = createAndStartManagedProfile(getDevice().getPrimaryUserId());
         installAppAsUser(DEVICE_SIDE_TEST_APK, newUser);
         allowGetActiveSessionForTest(newUser);
         runTestAsUser("testGetActiveSessions_noMediaSession", newUser);
diff --git a/hostsidetests/monkey/Android.mk b/hostsidetests/monkey/Android.mk
index 34305e8..052313c 100644
--- a/hostsidetests/monkey/Android.mk
+++ b/hostsidetests/monkey/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_CTS_TEST_PACKAGE := zzz.android.monkey
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
index 56b27f0..868a3bd 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
index 1cf9256..150d0b6 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_DEX_PREOPT := false
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/multiuser/Android.mk b/hostsidetests/multiuser/Android.mk
index a043b55..9827ca7 100644
--- a/hostsidetests/multiuser/Android.mk
+++ b/hostsidetests/multiuser/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.host.multiuser
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/net/Android.mk b/hostsidetests/net/Android.mk
index 88fbe0c..7270580 100644
--- a/hostsidetests/net/Android.mk
+++ b/hostsidetests/net/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/net/AndroidTest.xml b/hostsidetests/net/AndroidTest.xml
index ad7f81b..4a2e2e3 100644
--- a/hostsidetests/net/AndroidTest.xml
+++ b/hostsidetests/net/AndroidTest.xml
@@ -15,6 +15,7 @@
 -->
 <configuration description="Config for CTS net host test cases">
     <option name="config-descriptor:metadata" key="component" value="networking" />
+    <target_preparer class="com.android.cts.net.NetPolicyTestsPreparer" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsHostsideNetworkTests.jar" />
         <option name="runtime-hint" value="3m56s" />
diff --git a/hostsidetests/net/app/Android.mk b/hostsidetests/net/app/Android.mk
index 5e8c2b6..f094f3f 100644
--- a/hostsidetests/net/app/Android.mk
+++ b/hostsidetests/net/app/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_DEX_PREOPT := false
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/net/app2/Android.mk b/hostsidetests/net/app2/Android.mk
index 02071bf..9a4a30f 100644
--- a/hostsidetests/net/app2/Android.mk
+++ b/hostsidetests/net/app2/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_DEX_PREOPT := false
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/net/src/com/android/cts/net/NetPolicyTestsPreparer.java b/hostsidetests/net/src/com/android/cts/net/NetPolicyTestsPreparer.java
new file mode 100644
index 0000000..9b19554
--- /dev/null
+++ b/hostsidetests/net/src/com/android/cts/net/NetPolicyTestsPreparer.java
@@ -0,0 +1,75 @@
+/*
+ * 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.cts.net;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.ITargetPreparer;
+
+public class NetPolicyTestsPreparer implements ITargetPreparer, ITargetCleaner {
+    private final static String KEY_PAROLE_DURATION = "parole_duration";
+    private final static String DESIRED_PAROLE_DURATION = "0";
+
+    private boolean mAppIdleConstsUpdated;
+    private String mOriginalAppIdleConsts;
+
+    @Override
+    public void setUp(ITestDevice device, IBuildInfo buildInfo) throws DeviceNotAvailableException {
+        updateParoleDuration(device);
+        LogUtil.CLog.d("Original app_idle_constants: " + mOriginalAppIdleConsts);
+    }
+
+    @Override
+    public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable throwable)
+            throws DeviceNotAvailableException {
+        if (mAppIdleConstsUpdated) {
+            executeCmd(device, "settings put global app_idle_constants " + mOriginalAppIdleConsts);
+        }
+    }
+
+    /**
+     * Updates parole_duration with the desired value.
+     */
+    private void updateParoleDuration(ITestDevice device) throws DeviceNotAvailableException {
+        mOriginalAppIdleConsts = executeCmd(device, "settings get global app_idle_constants");
+        String newAppIdleConstants;
+        final String newConstant = KEY_PAROLE_DURATION + "=" + DESIRED_PAROLE_DURATION;
+        if (mOriginalAppIdleConsts == null || "null".equals(mOriginalAppIdleConsts)) {
+            // app_idle_constants is initially empty, so just assign the desired value.
+            newAppIdleConstants = newConstant;
+        } else if (mOriginalAppIdleConsts.contains(KEY_PAROLE_DURATION)) {
+            // app_idle_constants contains parole_duration, so replace it with the desired value.
+            newAppIdleConstants = mOriginalAppIdleConsts.replaceAll(
+                    KEY_PAROLE_DURATION + "=\\d+", newConstant);
+        } else {
+            // app_idle_constants didn't have parole_duration, so append the desired value.
+            newAppIdleConstants = mOriginalAppIdleConsts + "," + newConstant;
+        }
+        executeCmd(device, "settings put global app_idle_constants " + newAppIdleConstants);
+        mAppIdleConstsUpdated = true;
+    }
+
+    private String executeCmd(ITestDevice device, String cmd)
+            throws DeviceNotAvailableException {
+        final String output = device.executeShellCommand(cmd).trim();
+        LogUtil.CLog.d("Output for '%s': %s", cmd, output);
+        return output;
+    }
+}
diff --git a/hostsidetests/numberblocking/Android.mk b/hostsidetests/numberblocking/Android.mk
index 1aac30f..d57a0d9 100644
--- a/hostsidetests/numberblocking/Android.mk
+++ b/hostsidetests/numberblocking/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsHostsideNumberBlockingTestCases
 
diff --git a/hostsidetests/numberblocking/app/Android.mk b/hostsidetests/numberblocking/app/Android.mk
index e98e508..cfbccbe 100644
--- a/hostsidetests/numberblocking/app/Android.mk
+++ b/hostsidetests/numberblocking/app/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test legacy-android-test
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsHostsideNumberBlockingAppTest
 
diff --git a/hostsidetests/os/Android.mk b/hostsidetests/os/Android.mk
index 3b8a1cf..1b806c9 100644
--- a/hostsidetests/os/Android.mk
+++ b/hostsidetests/os/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.host.os
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/os/app/Android.mk b/hostsidetests/os/app/Android.mk
index 1897198..bc70dec 100644
--- a/hostsidetests/os/app/Android.mk
+++ b/hostsidetests/os/app/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceOsTestApp
 
diff --git a/hostsidetests/os/test-apps/Android.mk b/hostsidetests/os/test-apps/Android.mk
index 9fadf37..bd94fb5 100644
--- a/hostsidetests/os/test-apps/Android.mk
+++ b/hostsidetests/os/test-apps/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/os/test-apps/HostLinkVerificationApp/Android.mk b/hostsidetests/os/test-apps/HostLinkVerificationApp/Android.mk
index cfe131c..bd7eb5f 100644
--- a/hostsidetests/os/test-apps/HostLinkVerificationApp/Android.mk
+++ b/hostsidetests/os/test-apps/HostLinkVerificationApp/Android.mk
@@ -24,6 +24,6 @@
 LOCAL_PACKAGE_NAME := CtsHostLinkVerificationApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/test-apps/ProcfsTestApp/Android.mk b/hostsidetests/os/test-apps/ProcfsTestApp/Android.mk
index a168845..d3edc43 100644
--- a/hostsidetests/os/test-apps/ProcfsTestApp/Android.mk
+++ b/hostsidetests/os/test-apps/ProcfsTestApp/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_PACKAGE_NAME := CtsHostProcfsTestApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk
index 67335f4..9d0d001 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk
@@ -30,6 +30,6 @@
 
 LOCAL_PACKAGE_NAME := CtsStaticSharedLibConsumerApp1
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk
index 8ce6c9a..0c7351a 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk
@@ -27,6 +27,6 @@
 
 LOCAL_PACKAGE_NAME := CtsStaticSharedLibConsumerApp2
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk
index c1f8cd1..2e2a5e4 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.mk
index bd7a27e..9a3da9b 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS := --shared-lib
 
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk
index 04b794c..61adc17 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS := --shared-lib
 
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk
index b4c5248..0205259 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk
@@ -25,7 +25,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.mk
index 99acb17..1251f8b 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS := --shared-lib
 
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.mk
index ef92c71..2e5dc56 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS := --shared-lib
 
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.mk
index 5058191..69ed15f 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk b/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk
index da53850..54ebdd1 100644
--- a/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk
@@ -31,7 +31,7 @@
 
 LOCAL_MULTILIB := both
 
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
diff --git a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk
index bc09dc4..3d48af2 100644
--- a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk
@@ -20,13 +20,11 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
 LOCAL_JNI_SHARED_LIBRARIES := libstaticsharednativelibprovider
 
 LOCAL_PACKAGE_NAME := CtsStaticSharedNativeLibProvider
 
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk
index 0abc351d..fee38a7 100644
--- a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk
@@ -20,13 +20,11 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
 LOCAL_JNI_SHARED_LIBRARIES := libstaticsharednativelibprovider
 
 LOCAL_PACKAGE_NAME := CtsStaticSharedNativeLibProvider1
 
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/hostsidetests/sample/Android.mk b/hostsidetests/sample/Android.mk
index 427d72a..bc821ae 100644
--- a/hostsidetests/sample/Android.mk
+++ b/hostsidetests/sample/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsSampleHostTestCases
 
diff --git a/hostsidetests/sample/app/Android.mk b/hostsidetests/sample/app/Android.mk
index c69f29f..b3b6ad1 100644
--- a/hostsidetests/sample/app/Android.mk
+++ b/hostsidetests/sample/app/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsSampleDeviceApp
 
diff --git a/hostsidetests/sample/app2/Android.mk b/hostsidetests/sample/app2/Android.mk
index 4c20ae3..845f51a 100644
--- a/hostsidetests/sample/app2/Android.mk
+++ b/hostsidetests/sample/app2/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsSampleDeviceApp2
 
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index 5544dc6..f209153 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE_TAGS := optional
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsSecurityHostTestCases
diff --git a/hostsidetests/security/securityPatch/Bug-33452365/Android.mk b/hostsidetests/security/securityPatch/Bug-33452365/Android.mk
index 5178058..9c61dc0 100644
--- a/hostsidetests/security/securityPatch/Bug-33452365/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-33452365/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-33863407/Android.mk b/hostsidetests/security/securityPatch/Bug-33863407/Android.mk
index f1c32e1..563d66b 100644
--- a/hostsidetests/security/securityPatch/Bug-33863407/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-33863407/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-34328139/Android.mk b/hostsidetests/security/securityPatch/Bug-34328139/Android.mk
index cd8d541..bbdeb63 100644
--- a/hostsidetests/security/securityPatch/Bug-34328139/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-34328139/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35047217/Android.mk b/hostsidetests/security/securityPatch/Bug-35047217/Android.mk
index ccf6b5e..11d92c0 100644
--- a/hostsidetests/security/securityPatch/Bug-35047217/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35047217/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-35047780/Android.mk b/hostsidetests/security/securityPatch/Bug-35047780/Android.mk
index d4c91bb..9a0ccc4 100644
--- a/hostsidetests/security/securityPatch/Bug-35047780/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35047780/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-35048450/Android.mk b/hostsidetests/security/securityPatch/Bug-35048450/Android.mk
index ea9dd89..1c17d49 100644
--- a/hostsidetests/security/securityPatch/Bug-35048450/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35048450/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-35644815/Android.mk b/hostsidetests/security/securityPatch/Bug-35644815/Android.mk
index 1dd2950..1cced42 100644
--- a/hostsidetests/security/securityPatch/Bug-35644815/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35644815/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-36266767/Android.mk b/hostsidetests/security/securityPatch/Bug-36266767/Android.mk
index 2a1edd0..12493e2 100644
--- a/hostsidetests/security/securityPatch/Bug-36266767/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-36266767/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-36591162/Android.mk b/hostsidetests/security/securityPatch/Bug-36591162/Android.mk
index ee17cb7..9413b75 100644
--- a/hostsidetests/security/securityPatch/Bug-36591162/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-36591162/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-2016-10231/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-10231/Android.mk
index 3ba801e..34c2f5c 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-10231/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-10231/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2016-6730/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-6730/Android.mk
index 350a4fe..f716db3 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-6730/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-6730/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-6731/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-6731/Android.mk
index 4e14be4..4149b96 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-6731/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-6731/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-6732/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-6732/Android.mk
index 7c289a4..13fc65e 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-6732/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-6732/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-6733/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-6733/Android.mk
index a535f0b..c9721ac 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-6733/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-6733/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-6734/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-6734/Android.mk
index 9450db9..1cb417e 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-6734/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-6734/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-6735/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-6735/Android.mk
index d089c40..7def71d 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-6735/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-6735/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-6736/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-6736/Android.mk
index bb6efc8..c29bfbd 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-6736/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-6736/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8412/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8412/Android.mk
index 197690f..5b86c1f 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8412/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8412/Android.mk
@@ -22,14 +22,9 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8424/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8424/Android.mk
index 2b33fd4..985b7d8 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8424/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8424/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8425/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8425/Android.mk
index 8b1ab64..3f8f3c8 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8425/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8425/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8426/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8426/Android.mk
index c5c7521..39c4d84 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8426/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8426/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8427/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8427/Android.mk
index 5e4c323..84d5b26 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8427/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8427/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8428/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8428/Android.mk
index dd68436..d37a1ae 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8428/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8428/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8429/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8429/Android.mk
index 438a578..6616238 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8429/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8429/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8430/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8430/Android.mk
index f0a0e60..f877032 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8430/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8430/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8431/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8431/Android.mk
index ccfbab8..fb2116d 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8431/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8431/Android.mk
@@ -22,14 +22,9 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8432/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8432/Android.mk
index 235c323..745ce1e 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8432/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8432/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8434/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8434/Android.mk
index 8c8cc35..cba1876 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8434/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8434/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8435/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8435/Android.mk
index 6dbedc1..8191685 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8435/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8435/Android.mk
@@ -22,14 +22,9 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8444/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8444/Android.mk
index 2e667ab..034b621 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8444/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8444/Android.mk
@@ -22,14 +22,9 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8448/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8448/Android.mk
index 155f72b..4469fcc 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8448/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8448/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8449/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8449/Android.mk
index a905cc9..20afa92 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8449/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8449/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8460/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8460/Android.mk
index 51f8169..bf592df 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8460/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8460/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS := -Wall -W -g -O2 -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8482/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-8482/Android.mk
index 16ceff2..8762bd3 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-8482/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-8482/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2016-9120/Android.mk b/hostsidetests/security/securityPatch/CVE-2016-9120/Android.mk
index b5d138d..f3800454 100644
--- a/hostsidetests/security/securityPatch/CVE-2016-9120/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2016-9120/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0403/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0403/Android.mk
index bd84bec..df21f39 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0403/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0403/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0404/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0404/Android.mk
index 66978e0..c84040c 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0404/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0404/Android.mk
@@ -22,14 +22,10 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0429/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0429/Android.mk
index 495a935..8c74e4c 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0429/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0429/Android.mk
@@ -22,14 +22,9 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS += -Iinclude -fPIE
 LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0451/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0451/Android.mk
index 6e52fa7..445754c 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0451/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0451/Android.mk
@@ -23,7 +23,7 @@
 
 # Tag this module as a cts test artifact                                                                            \
  
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0462/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0462/Android.mk
index 46c773d..35531b4 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0462/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0462/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0564/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0564/Android.mk
index 91d154c..0a02b5e 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0564/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0564/Android.mk
@@ -23,7 +23,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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0576/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0576/Android.mk
index c62755c..28e49a5 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0576/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0576/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0577/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0577/Android.mk
index 0ef89c5..521bf98 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0577/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0577/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0579/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0579/Android.mk
index 494b8c5..dab0081 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0579/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0579/Android.mk
@@ -23,7 +23,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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0580/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0580/Android.mk
index 6350b07..ec3a6f6 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0580/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0580/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0586/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0586/Android.mk
index 393bf6c..1dc269d9 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0586/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0586/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 general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0705/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0705/Android.mk
index bbde6e2..d1df00e 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-0705/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-0705/Android.mk
@@ -23,7 +23,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-7369/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-7369/Android.mk
index 9d1d3d17..ee76324 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-7369/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-7369/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_SRC_FILES := poc.c
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-8263/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-8263/Android.mk
index 0d1d60b..759e884 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-8263/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-8263/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/activitymanager/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
index 6ca5278..b4e32db 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.server
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/app/Android.mk
index 9a5dcbc..67f2248 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceServicesTestApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index c31aec8..6427066 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -357,6 +357,42 @@
                   android:noHistory="true"
                   android:exported="true" />
 
+        <activity android:name=".ShowWhenLockedAttrActivity"
+                  android:showWhenLocked="true"
+                  android:exported="true" />
+
+        <activity android:name=".ShowWhenLockedAttrRemoveAttrActivity"
+                  android:showWhenLocked="true"
+                  android:exported="true" />
+
+        <activity android:name=".ShowWhenLockedAttrWithDialogActivity"
+                  android:showWhenLocked="true"
+                  android:exported="true" />
+
+        <activity android:name=".TurnScreenOnAttrActivity"
+                  android:turnScreenOn="true"
+                  android:exported="true" />
+
+        <activity android:name=".TurnScreenOnShowOnLockActivity"
+                  android:showWhenLocked="true"
+                  android:turnScreenOn="true"
+                  android:exported="true" />
+
+        <activity android:name=".TurnScreenOnAttrRemoveAttrActivity"
+                  android:turnScreenOn="true"
+                  android:showWhenLocked="true"
+                  android:exported="true" />
+
+        <activity android:name=".TurnScreenOnSingleTaskActivity"
+                  android:turnScreenOn="true"
+                  android:showWhenLocked="true"
+                  android:exported="true"
+                  android:launchMode="singleTask" />
+
+        <activity android:name=".TurnScreenOnAttrDismissKeyguardActivity"
+                  android:turnScreenOn="true"
+                  android:exported="true"/>
+
         <service android:name="com.android.cts.verifier.vr.MockVrListenerService"
                  android:exported="true"
                  android:enabled="true"
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
index 333e0d2..9d29917 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
@@ -34,6 +34,12 @@
     }
 
     @Override
+    protected void onStart() {
+        super.onResume();
+        Log.i(getTag(), "onStart");
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
         Log.i(getTag(), "onResume");
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrActivity.java
new file mode 100644
index 0000000..c53c485
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.server.cts;
+
+public class ShowWhenLockedAttrActivity extends AbstractLifecycleLogActivity {
+    private static final String TAG = ShowWhenLockedAttrActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrRemoveAttrActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrRemoveAttrActivity.java
new file mode 100644
index 0000000..dbad34d
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrRemoveAttrActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.server.cts;
+
+import android.os.Bundle;
+
+public class ShowWhenLockedAttrRemoveAttrActivity extends AbstractLifecycleLogActivity {
+    private static final String TAG = ShowWhenLockedAttrRemoveAttrActivity.class.getSimpleName();
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        setShowWhenLocked(false);
+    }
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrWithDialogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrWithDialogActivity.java
new file mode 100644
index 0000000..136706a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedAttrWithDialogActivity.java
@@ -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
+ */
+
+package android.server.cts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class ShowWhenLockedAttrWithDialogActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        new AlertDialog.Builder(this)
+                .setTitle("Dialog")
+                .show();
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrActivity.java
new file mode 100644
index 0000000..5e1f5d1
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrActivity.java
@@ -0,0 +1,26 @@
+/*
+ * 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.server.cts;
+
+public class TurnScreenOnAttrActivity extends AbstractLifecycleLogActivity {
+    private static final String TAG = TurnScreenOnAttrActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrDismissKeyguardActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrDismissKeyguardActivity.java
new file mode 100644
index 0000000..b1b860f
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrDismissKeyguardActivity.java
@@ -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
+ */
+
+package android.server.cts;
+
+import android.app.KeyguardManager;
+import android.os.Bundle;
+
+public class TurnScreenOnAttrDismissKeyguardActivity extends AbstractLifecycleLogActivity {
+    private static final String TAG = TurnScreenOnAttrDismissKeyguardActivity.class.getSimpleName();
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        ((KeyguardManager) getSystemService(KEYGUARD_SERVICE))
+                .requestDismissKeyguard(this, new KeyguardDismissLoggerCallback(this));
+    }
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrRemoveAttrActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrRemoveAttrActivity.java
new file mode 100644
index 0000000..29911fe
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnAttrRemoveAttrActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.server.cts;
+
+public class TurnScreenOnAttrRemoveAttrActivity extends AbstractLifecycleLogActivity {
+    private static final String TAG = TurnScreenOnAttrRemoveAttrActivity.class.getSimpleName();
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        setTurnScreenOn(false);
+    }
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnShowOnLockActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnShowOnLockActivity.java
new file mode 100644
index 0000000..57ff4fb
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnShowOnLockActivity.java
@@ -0,0 +1,26 @@
+/*
+ * 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.server.cts;
+
+public class TurnScreenOnShowOnLockActivity extends AbstractLifecycleLogActivity {
+    private static final String TAG = TurnScreenOnShowOnLockActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnSingleTaskActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnSingleTaskActivity.java
new file mode 100644
index 0000000..29c71d0
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnSingleTaskActivity.java
@@ -0,0 +1,26 @@
+/*
+ * 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.server.cts;
+
+public class TurnScreenOnSingleTaskActivity extends AbstractLifecycleLogActivity {
+    private static final String TAG = TurnScreenOnSingleTaskActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/Android.mk
index fa381fb..ddb08a2 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceDebuggableApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/Android.mk
index 95af843..98feb61 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceDisplaySizeApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/appSecondUid/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/appSecondUid/Android.mk
index 109279f..1456d22 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/appSecondUid/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appSecondUid/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceServicesTestSecondApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/appThirdUid/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/appThirdUid/Android.mk
index 73304b4..733f7a9 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/appThirdUid/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appThirdUid/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceServicesTestThirdApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
index c647be4..c3f4c5b 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -41,7 +41,10 @@
     private static final String MOVE_TASK_TO_BACK_ACTIVITY_NAME = "MoveTaskToBackActivity";
     private static final String SWIPE_REFRESH_ACTIVITY = "SwipeRefreshActivity";
     private static final String NOHISTORY_ACTIVITY = "NoHistoryActivity";
-
+    private static final String TURN_SCREEN_ON_ATTR_ACTIVITY_NAME = "TurnScreenOnAttrActivity";
+    private static final String TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY_NAME = "TurnScreenOnShowOnLockActivity";
+    private static final String TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY_NAME = "TurnScreenOnAttrRemoveAttrActivity";
+    private static final String TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME = "TurnScreenOnSingleTaskActivity";
 
     public void testTranslucentActivityOnTopOfPinnedStack() throws Exception {
         if (!supportsPip()) {
@@ -273,4 +276,68 @@
         mAmWmState.waitForHomeActivityVisible(mDevice);
         mAmWmState.assertHomeActivityVisible(true);
     }
+
+    public void testTurnScreenOnAttrNoLockScreen() throws Exception {
+        sleepDevice();
+        final String logSeparator = clearLogcat();
+        launchActivity(TURN_SCREEN_ON_ATTR_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] { TURN_SCREEN_ON_ATTR_ACTIVITY_NAME });
+        mAmWmState.assertVisibility(TURN_SCREEN_ON_ATTR_ACTIVITY_NAME, true);
+        assertTrue(isDisplayOn());
+        assertSingleLaunch(TURN_SCREEN_ON_ATTR_ACTIVITY_NAME, logSeparator);
+    }
+
+    public void testTurnScreenOnAttrWithLockScreen() throws Exception {
+        setUpLock();
+        sleepDevice();
+        final String logSeparator = clearLogcat();
+        launchActivity(TURN_SCREEN_ON_ATTR_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] { TURN_SCREEN_ON_ATTR_ACTIVITY_NAME });
+        assertFalse(isDisplayOn());
+        assertSingleLaunchAndStop(TURN_SCREEN_ON_ATTR_ACTIVITY_NAME, logSeparator);
+    }
+
+    public void testTurnScreenOnShowOnLockAttr() throws Exception {
+        sleepDevice();
+        final String logSeparator = clearLogcat();
+        launchActivity(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] { TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY_NAME });
+        mAmWmState.assertVisibility(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY_NAME, true);
+        assertTrue(isDisplayOn());
+        assertSingleLaunch(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY_NAME, logSeparator);
+    }
+
+    public void testTurnScreenOnAttrRemove() throws Exception {
+        sleepDevice();
+        String logSeparator = clearLogcat();
+        launchActivity(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {
+                TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY_NAME});
+        assertTrue(isDisplayOn());
+        assertSingleLaunch(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY_NAME, logSeparator);
+
+        sleepDevice();
+        logSeparator = clearLogcat();
+        launchActivity(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY_NAME);
+        assertFalse(isDisplayOn());
+        assertSingleStartAndStop(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY_NAME, logSeparator);
+    }
+
+    public void testTurnScreenOnSingleTask() throws Exception {
+        sleepDevice();
+        String logSeparator = clearLogcat();
+        launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] { TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME });
+        mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME, true);
+        assertTrue(isDisplayOn());
+        assertSingleLaunch(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME, logSeparator);
+
+        sleepDevice();
+        logSeparator = clearLogcat();
+        launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] { TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME });
+        mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME, true);
+        assertTrue(isDisplayOn());
+        assertSingleStart(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY_NAME, logSeparator);
+    }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAssistantStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAssistantStackTests.java
index 21146a4..b3c2af0 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAssistantStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAssistantStackTests.java
@@ -29,6 +29,7 @@
     private static final String TEST_ACTIVITY = "TestActivity";
     private static final String DOCKED_ACTIVITY = "DockedActivity";
     private static final String ASSISTANT_ACTIVITY = "AssistantActivity";
+    private static final String TRANSLUCENT_ASSISTANT_ACTIVITY = "TranslucentAssistantActivity";
     private static final String LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION =
             "LaunchAssistantActivityFromSession";
     private static final String LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK =
@@ -156,7 +157,7 @@
         launchHomeActivity();
         launchActivity(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
                 EXTRA_IS_TRANSLUCENT, String.valueOf(true));
-        mAmWmState.waitForValidState(mDevice, ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
+        mAmWmState.waitForValidState(mDevice, TRANSLUCENT_ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
         assertAssistantStackExists();
         mAmWmState.assertHomeActivityVisible(true);
 
@@ -166,7 +167,7 @@
         launchActivity(TEST_ACTIVITY);
         launchActivity(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
                 EXTRA_IS_TRANSLUCENT, String.valueOf(true));
-        mAmWmState.waitForValidState(mDevice, ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
+        mAmWmState.waitForValidState(mDevice, TRANSLUCENT_ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
         assertAssistantStackExists();
         mAmWmState.assertVisibility(TEST_ACTIVITY, true);
 
@@ -178,7 +179,7 @@
         mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
         launchActivity(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
                 EXTRA_IS_TRANSLUCENT, String.valueOf(true));
-        mAmWmState.waitForValidState(mDevice, ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
+        mAmWmState.waitForValidState(mDevice, TRANSLUCENT_ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
         assertAssistantStackExists();
         mAmWmState.assertVisibility(DOCKED_ACTIVITY, true);
         mAmWmState.assertVisibility(TEST_ACTIVITY, true);
@@ -213,6 +214,26 @@
         disableAssistant();
     }
 
+    public void testPinnedStackWithAssistant() throws Exception {
+        if (!supportsPip() || !supportsSplitScreenMultiWindow()) return;
+
+        enableAssistant();
+
+        // Launch a fullscreen activity and a PIP activity, then launch the assistant, and ensure
+        // that the test activity is still visible
+        launchActivity(TEST_ACTIVITY);
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+        launchActivity(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
+                EXTRA_IS_TRANSLUCENT, String.valueOf(true));
+        mAmWmState.waitForValidState(mDevice, TRANSLUCENT_ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
+        assertAssistantStackExists();
+        mAmWmState.assertVisibility(TRANSLUCENT_ASSISTANT_ACTIVITY, true);
+        mAmWmState.assertVisibility(PIP_ACTIVITY, true);
+        mAmWmState.assertVisibility(TEST_ACTIVITY, true);
+
+        disableAssistant();
+    }
+
     /**
      * Asserts that the assistant stack exists.
      */
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index 55b41c8..c6855f9 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -492,6 +492,16 @@
                 ALWAYS_FOCUSABLE_PIP_ACTIVITY)));
     }
 
+    public void testAutoEnterPictureInPictureNonFullscreenActivity() throws Exception {
+        if (!supportsPip()) return;
+
+        // Launch an auto-enter PIP activity, and a translucent activity on top. Ensure that the
+        // start of the translucent activity does not trigger the PIP activity to enter PIP.
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP_ON_PAUSE, "true");
+        launchActivity(TRANSLUCENT_TEST_ACTIVITY);
+        assertPinnedStackDoesNotExist();
+    }
+
     public void testDisallowMultipleTasksInPinnedStack() throws Exception {
         if (!supportsPip()) return;
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
index 3c1a626..837f006 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
@@ -31,18 +31,13 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        setLockCredential();
+        setUpLock();
     }
 
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
-        removeLockCredential();
-        // Dismiss active keyguard after credential is cleared, so
-        // keyguard doesn't ask for the stale credential.
-        pressBackButton();
-        sleepDevice();
-        wakeUpAndUnlockDevice();
+        tearDownLock();
     }
 
     public void testLockAndUnlock() throws Exception {
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
index 89bbb07..6411571 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
@@ -39,6 +39,7 @@
 
         // Remove screen lock
         mDevice.executeShellCommand("locksettings set-disabled true");
+        tearDownLock();
     }
 
     public void testKeyguardHidesActivity() throws Exception {
@@ -310,4 +311,44 @@
         assertNotNull(wallpaper);
         assertTrue(wallpaper.isShown());
     }
+
+    public void testDismissKeyguardAttrActivity_method_turnScreenOn() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+
+        final String activityName = "TurnScreenOnAttrDismissKeyguardActivity";
+        sleepDevice();
+
+        final String logSeparator = clearLogcat();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity(activityName);
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.assertVisibility(activityName, true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertOnDismissSucceededInLogcat(logSeparator);
+        assertTrue(isDisplayOn());
+    }
+
+    public void testDismissKeyguardAttrActivity_method_turnScreenOn_withSecureKeyguard() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+
+        final String activityName = "TurnScreenOnAttrDismissKeyguardActivity";
+
+        setUpLock();
+        sleepDevice();
+
+        final String logSeparator = clearLogcat();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity(activityName);
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        mAmWmState.assertVisibility(activityName, false);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertTrue(isDisplayOn());
+    }
+
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTransitionTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTransitionTests.java
index 05065aa..b1e80e9 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTransitionTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTransitionTests.java
@@ -103,4 +103,59 @@
         assertEquals("Picked wrong transition", TRANSIT_ACTIVITY_OPEN,
                 mAmWmState.getWmState().getLastTransition());
     }
+
+    public void testOccludeManifestAttr() throws Exception {
+         if (!isHandheld()) {
+             return;
+         }
+
+         String activityName = "ShowWhenLockedAttrActivity";
+
+         gotoKeyguard();
+         final String logSeparator = clearLogcat();
+         launchActivity(activityName);
+         mAmWmState.computeState(mDevice, new String[] {activityName});
+         assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_OCCLUDE,
+                 mAmWmState.getWmState().getLastTransition());
+         assertSingleLaunch(activityName, logSeparator);
+    }
+
+    public void testOccludeAttrRemove() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+
+        String activityName = "ShowWhenLockedAttrRemoveAttrActivity";
+
+        gotoKeyguard();
+        String logSeparator = clearLogcat();
+        launchActivity(activityName);
+        mAmWmState.computeState(mDevice, new String[] {activityName});
+        assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_OCCLUDE,
+                mAmWmState.getWmState().getLastTransition());
+        assertSingleLaunch(activityName, logSeparator);
+
+        gotoKeyguard();
+        logSeparator = clearLogcat();
+        launchActivity(activityName);
+        mAmWmState.computeState(mDevice, new String[] {activityName});
+        assertSingleStartAndStop(activityName, logSeparator);
+    }
+
+    public void testNewActivityDuringOccludedWithAttr() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+
+        String activityName1 = "ShowWhenLockedAttrActivity";
+        String activityName2 = "ShowWhenLockedAttrWithDialogActivity";
+
+        launchActivity(activityName1);
+        gotoKeyguard();
+        launchActivity(activityName2);
+        mAmWmState.computeState(mDevice, new String[] { activityName2 });
+        assertEquals("Picked wrong transition", TRANSIT_ACTIVITY_OPEN,
+                mAmWmState.getWmState().getLastTransition());
+    }
+
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/translucentapp/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/translucentapp/Android.mk
index e20bbb5..3b075e1 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/translucentapp/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/translucentapp/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceTranslucentTestApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 702709b..304fa55 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -265,6 +265,7 @@
         mInitialAccelerometerRotation = getAccelerometerRotation();
         mUserRotation = getUserRotation();
         mFontScale = getFontScale();
+        tearDownLock();
     }
 
     @Override
@@ -585,7 +586,7 @@
         return result;
     }
 
-    private boolean isDisplayOn() throws DeviceNotAvailableException {
+    protected boolean isDisplayOn() throws DeviceNotAvailableException {
         final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand("dumpsys power", outputReceiver);
 
@@ -927,7 +928,124 @@
         return filteredResult;
     }
 
+    void assertSingleLaunch(String activityName, String logSeparator) throws DeviceNotAvailableException {
+        int retriesLeft = 5;
+        String resultString;
+        do {
+            resultString = validateLifecycleCounts(activityName, logSeparator, 1 /* createCount */,
+                    1 /* startCount */, 1 /* resumeCount */, 0 /* pauseCount */, 0 /* stopCount */,
+                    0 /* destroyCount */);
+            if (resultString != null) {
+                log("***Waiting for valid lifecycle state: " + resultString);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+
+        assertNull(resultString, resultString);
+    }
+
+    public void assertSingleLaunchAndStop(String activityName, String logSeparator) throws DeviceNotAvailableException {
+        int retriesLeft = 5;
+        String resultString;
+        do {
+            resultString = validateLifecycleCounts(activityName, logSeparator, 1 /* createCount */,
+                    1 /* startCount */, 1 /* resumeCount */, 1 /* pauseCount */, 1 /* stopCount */,
+                    0 /* destroyCount */);
+            if (resultString != null) {
+                log("***Waiting for valid lifecycle state: " + resultString);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+
+        assertNull(resultString, resultString);
+    }
+
+    public void assertSingleStartAndStop(String activityName, String logSeparator) throws DeviceNotAvailableException {
+        int retriesLeft = 5;
+        String resultString;
+        do {
+            resultString =  validateLifecycleCounts(activityName, logSeparator, 0 /* createCount */,
+                    1 /* startCount */, 1 /* resumeCount */, 1 /* pauseCount */, 1 /* stopCount */,
+                    0 /* destroyCount */);
+            if (resultString != null) {
+                log("***Waiting for valid lifecycle state: " + resultString);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+
+        assertNull(resultString, resultString);
+    }
+
+    void assertSingleStart(String activityName, String logSeparator) throws DeviceNotAvailableException {
+        int retriesLeft = 5;
+        String resultString;
+        do {
+            resultString = validateLifecycleCounts(activityName, logSeparator, 0 /* createCount */,
+                    1 /* startCount */, 1 /* resumeCount */, 0 /* pauseCount */, 0 /* stopCount */,
+                    0 /* destroyCount */);
+            if (resultString != null) {
+                log("***Waiting for valid lifecycle state: " + resultString);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+
+        assertNull(resultString, resultString);
+    }
+
+    private String validateLifecycleCounts(String activityName, String logSeparator,
+            int createCount, int startCount, int resumeCount, int pauseCount, int stopCount,
+            int destroyCount) throws DeviceNotAvailableException {
+
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+                logSeparator);
+
+        if (lifecycleCounts.mCreateCount != createCount) {
+            return activityName + " created " + lifecycleCounts.mCreateCount + " times.";
+        }
+        if (lifecycleCounts.mStartCount != startCount) {
+            return activityName + " started " + lifecycleCounts.mStartCount + " times.";
+        }
+        if (lifecycleCounts.mResumeCount != resumeCount) {
+            return activityName + " resumed " + lifecycleCounts.mResumeCount + " times.";
+        }
+        if (lifecycleCounts.mPauseCount != pauseCount) {
+            return activityName + " paused " + lifecycleCounts.mPauseCount + " times.";
+        }
+        if (lifecycleCounts.mStopCount != stopCount) {
+            return activityName + " stopped " + lifecycleCounts.mStopCount + " times.";
+        }
+        if (lifecycleCounts.mDestroyCount != destroyCount) {
+            return activityName + " destroyed " + lifecycleCounts.mDestroyCount + " times.";
+        }
+        return null;
+    }
+
     private static final Pattern sCreatePattern = Pattern.compile("(.+): onCreate");
+    private static final Pattern sStartPattern = Pattern.compile("(.+): onStart");
     private static final Pattern sResumePattern = Pattern.compile("(.+): onResume");
     private static final Pattern sPausePattern = Pattern.compile("(.+): onPause");
     private static final Pattern sConfigurationChangedPattern =
@@ -1030,6 +1148,7 @@
 
     class ActivityLifecycleCounts {
         int mCreateCount;
+        int mStartCount;
         int mResumeCount;
         int mConfigurationChangedCount;
         int mLastConfigurationChangedLineIndex;
@@ -1056,6 +1175,12 @@
                     continue;
                 }
 
+                matcher = sStartPattern.matcher(line);
+                if (matcher.matches()) {
+                    mStartCount++;
+                    continue;
+                }
+
                 matcher = sResumePattern.matcher(line);
                 if (matcher.matches()) {
                     mResumeCount++;
@@ -1228,4 +1353,17 @@
             }
         }
     }
+
+    void setUpLock() throws Exception {
+        setLockCredential();
+    }
+
+    void tearDownLock() throws Exception {
+        removeLockCredential();
+        // Dismiss active keyguard after credential is cleared, so
+        // keyguard doesn't ask for the stale credential.
+        pressBackButton();
+        sleepDevice();
+        wakeUpAndUnlockDevice();
+    }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
index 2ce16d8..0739743 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.server.cts
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowapp/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowapp/Android.mk
index 1bdeeb4..dc2485d 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowapp/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowapp/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceAlertWindowTestApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowappsdk25/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowappsdk25/Android.mk
index 4a4c0c7..5246c94 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowappsdk25/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/alertwindowappsdk25/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_SDK_VERSION := 25
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceAlertWindowTestAppSdk25
 
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/Android.mk
index 4cd44ed..12a04ed 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDragAndDropSourceApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/Android.mk
index 10fe386..cb43a8b 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDragAndDropTargetApp
 
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/Android.mk
index 2907241..a33e1bc 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := 23
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDragAndDropTargetAppSdk23
 
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
index 7719315..d6e82d3 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDeviceWindowFramesTestApp
 
diff --git a/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk b/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk
index 3871c0d..d6077a4 100644
--- a/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutBackupLauncher1
 
diff --git a/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk b/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk
index 65a1a28..8f124a0 100644
--- a/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutBackupLauncher2
 
diff --git a/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk b/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk
index ab0b4ce..9883e5c 100644
--- a/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutBackupLauncher3
 
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk b/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk
index 179f2be..72da903 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutBackupPublisher1
 
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk b/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk
index 6376c86..286dded 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutBackupPublisher2
 
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk b/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk
index f59093b..f1421d1 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutBackupPublisher3
 
diff --git a/hostsidetests/shortcuts/deviceside/multiuser/Android.mk b/hostsidetests/shortcuts/deviceside/multiuser/Android.mk
index f48b4ce..619bdfe 100644
--- a/hostsidetests/shortcuts/deviceside/multiuser/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/multiuser/Android.mk
@@ -19,7 +19,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutMultiuserTest
 
diff --git a/hostsidetests/shortcuts/deviceside/upgrade/Android.mk b/hostsidetests/shortcuts/deviceside/upgrade/Android.mk
index d9d7079..ae0bf75 100644
--- a/hostsidetests/shortcuts/deviceside/upgrade/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/upgrade/Android.mk
@@ -21,7 +21,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutUpgradeVersion1
 
@@ -52,7 +52,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutUpgradeVersion2
 
diff --git a/hostsidetests/shortcuts/hostside/Android.mk b/hostsidetests/shortcuts/hostside/Android.mk
index 6eeb001..f8bf4dd 100644
--- a/hostsidetests/shortcuts/hostside/Android.mk
+++ b/hostsidetests/shortcuts/hostside/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/sustainedperf/Android.mk b/hostsidetests/sustainedperf/Android.mk
index 3187415..745a0b4 100644
--- a/hostsidetests/sustainedperf/Android.mk
+++ b/hostsidetests/sustainedperf/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MODULE := CtsSustainedPerformanceHostTestCases
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
diff --git a/hostsidetests/sustainedperf/app/Android.mk b/hostsidetests/sustainedperf/app/Android.mk
index 473621a..f995837 100644
--- a/hostsidetests/sustainedperf/app/Android.mk
+++ b/hostsidetests/sustainedperf/app/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsSustainedPerformanceDeviceTestApp
 
diff --git a/hostsidetests/sustainedperf/dhrystone/Android.mk b/hostsidetests/sustainedperf/dhrystone/Android.mk
index b7a2baf..abcbe669 100644
--- a/hostsidetests/sustainedperf/dhrystone/Android.mk
+++ b/hostsidetests/sustainedperf/dhrystone/Android.mk
@@ -14,5 +14,5 @@
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 include $(BUILD_EXECUTABLE)
diff --git a/hostsidetests/sustainedperf/shadertoy_android/Android.mk b/hostsidetests/sustainedperf/shadertoy_android/Android.mk
index c9a5000..ba6bf64 100644
--- a/hostsidetests/sustainedperf/shadertoy_android/Android.mk
+++ b/hostsidetests/sustainedperf/shadertoy_android/Android.mk
@@ -33,6 +33,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 include $(BUILD_PACKAGE)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/systemui/Android.mk b/hostsidetests/systemui/Android.mk
index a2bcf05..ba437b9 100644
--- a/hostsidetests/systemui/Android.mk
+++ b/hostsidetests/systemui/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/systemui/app/Android.mk b/hostsidetests/systemui/app/Android.mk
index 6e45818..fed7a9f 100644
--- a/hostsidetests/systemui/app/Android.mk
+++ b/hostsidetests/systemui/app/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsSystemUiDeviceApp
 
diff --git a/hostsidetests/theme/Android.mk b/hostsidetests/theme/Android.mk
index c79bd13..3764442 100644
--- a/hostsidetests/theme/Android.mk
+++ b/hostsidetests/theme/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/theme/app/Android.mk b/hostsidetests/theme/app/Android.mk
index cb97bc0..de63355 100644
--- a/hostsidetests/theme/app/Android.mk
+++ b/hostsidetests/theme/app/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_PACKAGE_NAME := CtsThemeDeviceApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := 23
 
diff --git a/hostsidetests/trustedvoice/Android.mk b/hostsidetests/trustedvoice/Android.mk
index a0bc98b..34806f3 100644
--- a/hostsidetests/trustedvoice/Android.mk
+++ b/hostsidetests/trustedvoice/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.host.trustedvoice
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/trustedvoice/app/Android.mk b/hostsidetests/trustedvoice/app/Android.mk
index c9140e5..5127579 100644
--- a/hostsidetests/trustedvoice/app/Android.mk
+++ b/hostsidetests/trustedvoice/app/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsTrustedVoiceApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/tv/Android.mk b/hostsidetests/tv/Android.mk
index 687252d..79f976a 100644
--- a/hostsidetests/tv/Android.mk
+++ b/hostsidetests/tv/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.tv.hostsidetv
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/tv/app/Android.mk b/hostsidetests/tv/app/Android.mk
index c26a46a..5ffdeb4 100644
--- a/hostsidetests/tv/app/Android.mk
+++ b/hostsidetests/tv/app/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_DEX_PREOPT := false
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/tv/app2/Android.mk b/hostsidetests/tv/app2/Android.mk
index ef34420..76ae765 100644
--- a/hostsidetests/tv/app2/Android.mk
+++ b/hostsidetests/tv/app2/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/tzdata/Android.mk b/hostsidetests/tzdata/Android.mk
index 6eab01c..50c22ab 100644
--- a/hostsidetests/tzdata/Android.mk
+++ b/hostsidetests/tzdata/Android.mk
@@ -23,11 +23,11 @@
 
 LOCAL_JAVA_LIBRARIES := tradefed
 
-LOCAL_STATIC_JAVA_LIBRARIES := tzdata-testing-host tzdata_shared2-host tzdata_tools2-host
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata-testing-host time_zone_distro-host time_zone_distro_tools-host
 
 LOCAL_CTS_TEST_PACKAGE := android.host.tzdata
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
index c059e89..2e9707c 100644
--- a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
+++ b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
@@ -18,6 +18,9 @@
 
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.timezone.distro.DistroVersion;
+import com.android.timezone.distro.TimeZoneDistro;
+import com.android.timezone.distro.tools.TimeZoneDistroBuilder;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -28,10 +31,7 @@
 import java.util.Comparator;
 import java.util.StringJoiner;
 import java.util.function.Consumer;
-import libcore.tzdata.shared2.DistroVersion;
-import libcore.tzdata.shared2.TimeZoneDistro;
 import libcore.tzdata.testing.ZoneInfoTestHelper;
-import libcore.tzdata.update2.tools.TimeZoneDistroBuilder;
 
 import static org.junit.Assert.assertArrayEquals;
 
@@ -56,28 +56,28 @@
 
     /**
      * The name of the directory containing the current time zone rules data beneath
-     * {@link #mDataDir}.  Also known to {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and
+     * {@link #mDataDir}.  Also known to {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and
      * tzdatacheck.cpp.
      */
     private static final String CURRENT_DIR_NAME = "current";
 
     /**
      * The name of the directory containing the staged time zone rules data beneath
-     * {@link #mDataDir}.  Also known to {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and
+     * {@link #mDataDir}.  Also known to {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and
      * tzdatacheck.cpp.
      */
     private static final String STAGED_DIR_NAME = "staged";
 
     /**
      * The name of the file inside the staged directory that indicates the staged operation is an
-     * uninstall. Also known to {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and
+     * uninstall. Also known to {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and
      * tzdatacheck.cpp.
      */
     private static final String UNINSTALL_TOMBSTONE_FILE_NAME = "STAGED_UNINSTALL_TOMBSTONE";
 
     /**
      * The name of the /system time zone data file. Also known to
-     * {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and tzdatacheck.cpp.
+     * {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and tzdatacheck.cpp.
      */
     private static final String SYSTEM_TZDATA_FILE_NAME = "tzdata";
 
@@ -228,8 +228,8 @@
 
         // Create a current installed distro.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        TimeZoneDistro distro = createValidDistroBuilder().build();
-        unpackOnHost(dataCurrentDir, distro);
+        byte[] distroBytes = createValidDistroBuilder().buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -252,8 +252,8 @@
 
         // Create a staged install.
         PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        TimeZoneDistro distro = createValidDistroBuilder().build();
-        unpackOnHost(dataStagedDir, distro);
+        byte[] distroBytes = createValidDistroBuilder().buildBytes();
+        unpackOnHost(dataStagedDir, distroBytes);
 
         // Create a file with the same name as the directory that tzdatacheck expects.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -268,7 +268,7 @@
 
         // Assert the device was left in a valid "installed" state.
         assertDevicePathDoesNotExist(dataStagedDir);
-        assertDeviceDirContainsDistro(dataCurrentDir, distro);
+        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
     }
 
     // {dataDir}/staged contains an install, but there is nothing to replace.
@@ -282,8 +282,8 @@
 
         // Create a staged install.
         PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        TimeZoneDistro stagedDistro = createValidDistroBuilder().build();
-        unpackOnHost(dataStagedDir, stagedDistro);
+        byte[] stagedDistroBytes = createValidDistroBuilder().buildBytes();
+        unpackOnHost(dataStagedDir, stagedDistroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -294,7 +294,7 @@
 
         // Assert the device was left in a valid "installed" state.
         assertDevicePathDoesNotExist(dataStagedDir);
-        assertDeviceDirContainsDistro(dataCurrentDir, stagedDistro);
+        assertDeviceDirContainsDistro(dataCurrentDir, stagedDistroBytes);
     }
 
     // {dataDir}/staged contains an install, and there is something to replace.
@@ -311,17 +311,17 @@
 
         // Create a staged uninstall.
         PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        TimeZoneDistro stagedDistro = createValidDistroBuilder()
+        byte[] stagedDistroBytes = createValidDistroBuilder()
                 .setDistroVersion(stagedDistroVersion)
-                .build();
-        unpackOnHost(dataStagedDir, stagedDistro);
+                .buildBytes();
+        unpackOnHost(dataStagedDir, stagedDistroBytes);
 
         // Create a current installed distro.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        TimeZoneDistro currentDistro = createValidDistroBuilder()
+        byte[] currentDistroBytes = createValidDistroBuilder()
                 .setDistroVersion(currentDistroVersion)
-                .build();
-        unpackOnHost(dataCurrentDir, currentDistro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, currentDistroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -333,7 +333,7 @@
         // Assert the device was left in a valid "installed" state.
         // The stagedDistro should now be the one in the current dir.
         assertDevicePathDoesNotExist(dataStagedDir);
-        assertDeviceDirContainsDistro(dataCurrentDir, stagedDistro);
+        assertDeviceDirContainsDistro(dataCurrentDir, stagedDistroBytes);
     }
 
     // {dataDir}/staged contains an invalid install, and there is something to replace.
@@ -347,15 +347,15 @@
 
         // Create a staged uninstall which contains invalid.
         PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        TimeZoneDistro stagedDistro = createValidDistroBuilder()
+        byte[] stagedDistroBytes = createValidDistroBuilder()
                 .clearVersionForTests()
-                .buildUnvalidated();
-        unpackOnHost(dataStagedDir, stagedDistro);
+                .buildUnvalidatedBytes();
+        unpackOnHost(dataStagedDir, stagedDistroBytes);
 
         // Create a current installed distro.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        TimeZoneDistro currentDistro = createValidDistroBuilder().build();
-        unpackOnHost(dataCurrentDir, currentDistro);
+        byte[] currentDistroBytes = createValidDistroBuilder().buildBytes();
+        unpackOnHost(dataCurrentDir, currentDistroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -413,10 +413,10 @@
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        TimeZoneDistro distroWithoutAVersionFile = createValidDistroBuilder()
+        byte[] distroWithoutAVersionFileBytes = createValidDistroBuilder()
                 .clearVersionForTests()
-                .buildUnvalidated();
-        unpackOnHost(dataCurrentDir, distroWithoutAVersionFile);
+                .buildUnvalidatedBytes();
+        unpackOnHost(dataCurrentDir, distroWithoutAVersionFileBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -435,7 +435,7 @@
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        unpackOnHost(dataCurrentDir, createValidDistroBuilder().build());
+        unpackOnHost(dataCurrentDir, createValidDistroBuilder().buildBytes());
         // Replace the distro version file with a short file.
         Path distroVersionFile =
                 dataCurrentDir.hostPath.resolve(TimeZoneDistro.DISTRO_VERSION_FILE_NAME);
@@ -459,7 +459,7 @@
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        unpackOnHost(dataCurrentDir, createValidDistroBuilder().build());
+        unpackOnHost(dataCurrentDir, createValidDistroBuilder().buildBytes());
 
         // Replace the distro version file with junk.
         Path distroVersionFile =
@@ -489,10 +489,10 @@
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
         DistroVersion oldMajorDistroVersion = new DistroVersion(
                 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION - 1, 1, VALID_RULES_VERSION, 1);
-        TimeZoneDistro distro = createValidDistroBuilder()
+        byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(oldMajorDistroVersion)
-                .build();
-        unpackOnHost(dataCurrentDir, distro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -515,10 +515,10 @@
                 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION + 1,
                 DistroVersion.CURRENT_FORMAT_MINOR_VERSION,
                 VALID_RULES_VERSION, VALID_REVISION);
-        TimeZoneDistro distro = createValidDistroBuilder()
+        byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(newMajorDistroVersion)
-                .build();
-        unpackOnHost(dataCurrentDir, distro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -541,10 +541,10 @@
                 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
                 DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
                 VALID_RULES_VERSION, 1);
-        TimeZoneDistro distro = createValidDistroBuilder()
+        byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(oldMinorDistroVersion)
-                .build();
-        unpackOnHost(dataCurrentDir, distro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -568,10 +568,10 @@
                 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
                 DistroVersion.CURRENT_FORMAT_MINOR_VERSION + 1,
                 VALID_RULES_VERSION, VALID_REVISION);
-        TimeZoneDistro distro = createValidDistroBuilder()
+        byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(newMajorDistroVersion)
-                .build();
-        unpackOnHost(dataCurrentDir, distro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -580,7 +580,7 @@
         assertEquals(0, runTzDataCheckOnDevice());
 
         // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, distro);
+        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
     }
 
     // {dataDir}/current is valid but the tzdata file in /system is missing.
@@ -589,8 +589,8 @@
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        TimeZoneDistro validDistro = createValidDistroBuilder().build();
-        unpackOnHost(dataCurrentDir, validDistro);
+        byte[] validDistroBytes = createValidDistroBuilder().buildBytes();
+        unpackOnHost(dataCurrentDir, validDistroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -599,7 +599,7 @@
         assertEquals(6, runTzDataCheckOnDevice());
 
         // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, validDistro);
+        assertDeviceDirContainsDistro(dataCurrentDir, validDistroBytes);
     }
 
     // {dataDir}/current is valid but the tzdata file in /system has an invalid header.
@@ -610,8 +610,8 @@
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        TimeZoneDistro validDistro = createValidDistroBuilder().build();
-        unpackOnHost(dataCurrentDir, validDistro);
+        byte[] validDistroBytes = createValidDistroBuilder().buildBytes();
+        unpackOnHost(dataCurrentDir, validDistroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -620,7 +620,7 @@
         assertEquals(7, runTzDataCheckOnDevice());
 
         // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, validDistro);
+        assertDeviceDirContainsDistro(dataCurrentDir, validDistroBytes);
     }
 
     // {dataDir}/current is valid and the tzdata file in /system is older.
@@ -635,11 +635,11 @@
         DistroVersion distroVersion = new DistroVersion(
                 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
                 DistroVersion.CURRENT_FORMAT_MINOR_VERSION, distroRulesVersion, VALID_REVISION);
-        TimeZoneDistro distro = createValidDistroBuilder()
+        byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(distroVersion)
                 .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
-                .build();
-        unpackOnHost(dataCurrentDir, distro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -648,7 +648,7 @@
         assertEquals(0, runTzDataCheckOnDevice());
 
         // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, distro);
+        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
     }
 
     // {dataDir}/current is valid and the tzdata file in /system is the same (and should be kept).
@@ -662,11 +662,11 @@
         DistroVersion distroVersion = new DistroVersion(
                 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
                 DistroVersion.CURRENT_FORMAT_MINOR_VERSION, systemRulesVersion, VALID_REVISION);
-        TimeZoneDistro distro = createValidDistroBuilder()
+        byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(distroVersion)
                 .setTzDataFile(createValidTzDataBytes(systemRulesVersion))
-                .build();
-        unpackOnHost(dataCurrentDir, distro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -675,7 +675,7 @@
         assertEquals(0, runTzDataCheckOnDevice());
 
         // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, distro);
+        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
     }
 
     // {dataDir}/current is valid and the tzdata file in /system is the newer.
@@ -692,11 +692,11 @@
                 DistroVersion.CURRENT_FORMAT_MINOR_VERSION,
                 distroRulesVersion,
                 VALID_REVISION);
-        TimeZoneDistro distro = createValidDistroBuilder()
+        byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(distroVersion)
                 .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
-                .build();
-        unpackOnHost(dataCurrentDir, distro);
+                .buildBytes();
+        unpackOnHost(dataCurrentDir, distroBytes);
 
         // Push the host test directory and contents to the device.
         pushHostTestDirToDevice();
@@ -722,9 +722,9 @@
         new FileOutputStream(uninstallTombstoneFile.hostFile()).close();
     }
 
-    private static void unpackOnHost(PathPair path, TimeZoneDistro distro) throws Exception {
+    private static void unpackOnHost(PathPair path, byte[] distroBytes) throws Exception {
         createHostDirectory(path);
-        distro.extractTo(path.hostFile());
+        new TimeZoneDistro(distroBytes).extractTo(path.hostFile());
     }
 
     private static TimeZoneDistroBuilder createValidDistroBuilder() throws Exception {
@@ -910,7 +910,7 @@
         assertTrue(getDevice().doesFileExist(path.devicePath));
     }
 
-    private void assertDeviceDirContainsDistro(PathPair distroPath, TimeZoneDistro expectedDistro)
+    private void assertDeviceDirContainsDistro(PathPair distroPath, byte[] expectedDistroBytes)
             throws Exception {
         // Pull back just the version file and compare it.
         File localFile = mTestRootDir.createSubPath("temp.file").hostFile();
@@ -921,7 +921,8 @@
                     getDevice().pullFile(remoteVersionFile, localFile));
 
             byte[] bytes = Files.readAllBytes(localFile.toPath());
-            assertArrayEquals(bytes, expectedDistro.getDistroVersion().toBytes());
+            assertArrayEquals(bytes,
+                    new TimeZoneDistro(expectedDistroBytes).getDistroVersion().toBytes());
         } finally {
             localFile.delete();
         }
diff --git a/hostsidetests/ui/Android.mk b/hostsidetests/ui/Android.mk
index be29fdd..af7e2c9 100644
--- a/hostsidetests/ui/Android.mk
+++ b/hostsidetests/ui/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.ui.cts
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/ui/appA/Android.mk b/hostsidetests/ui/appA/Android.mk
index 4699e6c..7da5606 100644
--- a/hostsidetests/ui/appA/Android.mk
+++ b/hostsidetests/ui/appA/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsDeviceTaskSwitchingAppA
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/ui/appB/Android.mk b/hostsidetests/ui/appB/Android.mk
index 39ef2c9..07e2858 100644
--- a/hostsidetests/ui/appB/Android.mk
+++ b/hostsidetests/ui/appB/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsDeviceTaskSwitchingAppB
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/ui/control/Android.mk b/hostsidetests/ui/control/Android.mk
index 771431d..688ace7 100644
--- a/hostsidetests/ui/control/Android.mk
+++ b/hostsidetests/ui/control/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsDeviceTaskSwitchingControl
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/usage/Android.mk b/hostsidetests/usage/Android.mk
index dd0eb86..ff4f5e0 100644
--- a/hostsidetests/usage/Android.mk
+++ b/hostsidetests/usage/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.host.app.usage
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/usage/app/Android.mk b/hostsidetests/usage/app/Android.mk
index 0d765e7..59626d6 100644
--- a/hostsidetests/usage/app/Android.mk
+++ b/hostsidetests/usage/app/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_PACKAGE_NAME := CtsAppUsageTestApp
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/usb/Android.mk b/hostsidetests/usb/Android.mk
index 47b1f13..f08261e 100644
--- a/hostsidetests/usb/Android.mk
+++ b/hostsidetests/usb/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.usb
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/usb/SerialTestApp/Android.mk b/hostsidetests/usb/SerialTestApp/Android.mk
index 62bc7e2..2ddf30f 100644
--- a/hostsidetests/usb/SerialTestApp/Android.mk
+++ b/hostsidetests/usb/SerialTestApp/Android.mk
@@ -29,6 +29,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/webkit/Android.mk b/hostsidetests/webkit/Android.mk
index 897940b..663a079 100644
--- a/hostsidetests/webkit/Android.mk
+++ b/hostsidetests/webkit/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.webkit.hostside
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/webkit/app/Android.mk b/hostsidetests/webkit/app/Android.mk
index 28c0c01..60e9f3f 100644
--- a/hostsidetests/webkit/app/Android.mk
+++ b/hostsidetests/webkit/app/Android.mk
@@ -38,6 +38,6 @@
 LOCAL_DEX_PREOPT := false
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/suite/audio_quality/lib/Android.mk b/suite/audio_quality/lib/Android.mk
index cd19e85..2b3c22a 100644
--- a/suite/audio_quality/lib/Android.mk
+++ b/suite/audio_quality/lib/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-cpp-files)
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/src
 LOCAL_STATIC_LIBRARIES += libutils liblog libtinyalsa libcutils libtinyxml2
-LOCAL_CFLAGS:= -g -fno-exceptions
+LOCAL_CFLAGS:= -g -fno-exceptions -Wno-unused-parameter
 LOCAL_LDFLAGS:= -g -lrt -ldl -lm -fno-exceptions
 LOCAL_MODULE_HOST_OS := linux
 LOCAL_MODULE:= libcts_audio_quality
diff --git a/suite/audio_quality/test/Android.mk b/suite/audio_quality/test/Android.mk
index 7a84802..f8fe13c 100644
--- a/suite/audio_quality/test/Android.mk
+++ b/suite/audio_quality/test/Android.mk
@@ -33,7 +33,7 @@
 # need to keep everything in libcts_.. Otherwise, linker will drop some
 # functions and linker error happens
 LOCAL_WHOLE_STATIC_LIBRARIES := libcts_audio_quality
-LOCAL_CFLAGS:= -g -fno-exceptions
+LOCAL_CFLAGS:= -g -fno-exceptions -Wno-unused-parameter
 LOCAL_LDFLAGS:= -g -lrt -ldl -lm -fno-exceptions -lpthread
 LOCAL_CXX_STL := libc++_static
 LOCAL_MODULE_HOST_OS := linux
diff --git a/suite/audio_quality/test/LogTest.cpp b/suite/audio_quality/test/LogTest.cpp
index 4412338..51cde10 100644
--- a/suite/audio_quality/test/LogTest.cpp
+++ b/suite/audio_quality/test/LogTest.cpp
@@ -14,6 +14,7 @@
  * the License.
  */
 
+#include <inttypes.h>
 #include <stdint.h>
 #include <gtest/gtest.h>
 
@@ -46,12 +47,14 @@
     int64_t d = 3;
     int64_t e = 4;
     int64_t f = 5;
-    printf("printf %lld %lld %lld %lld %lld %lld\n", a, b, c, d, e, f);
-    LOGD(  "logd   %lld %lld %lld %lld %lld %lld", a, b, c, d, e, f);
-    LOGV(  "logv   %lld %lld %lld %lld %lld %lld", a, b, c, d, e, f);
-    LOGI(  "logi   %lld %lld %lld %lld %lld %lld", a, b, c, d, e, f);
-    LOGW(  "logw   %lld %lld %lld %lld %lld %lld", a, b, c, d, e, f);
-    LOGE(  "loge   %lld %lld %lld %lld %lld %lld", a, b, c, d, e, f);
+#define PrintABCDEF "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 \
+    " %" PRId64
+    printf("printf " PrintABCDEF "\n", a, b, c, d, e, f);
+    LOGD(  "logd   " PrintABCDEF, a, b, c, d, e, f);
+    LOGV(  "logv   " PrintABCDEF, a, b, c, d, e, f);
+    LOGI(  "logi   " PrintABCDEF, a, b, c, d, e, f);
+    LOGW(  "logw   " PrintABCDEF, a, b, c, d, e, f);
+    LOGE(  "loge   " PrintABCDEF, a, b, c, d, e, f);
 
     Log::Instance()->setLogLevel(level);
 }
diff --git a/tests/JobScheduler/Android.mk b/tests/JobScheduler/Android.mk
index ae1fa4d..8b70308 100755
--- a/tests/JobScheduler/Android.mk
+++ b/tests/JobScheduler/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_PACKAGE_NAME := CtsJobSchedulerTestCases
diff --git a/tests/JobScheduler/jobperm/Android.mk b/tests/JobScheduler/jobperm/Android.mk
index ca00ca7..f54f8d6 100644
--- a/tests/JobScheduler/jobperm/Android.mk
+++ b/tests/JobScheduler/jobperm/Android.mk
@@ -26,7 +26,7 @@
     $(call all-java-files-under, src) \
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsJobSchedulerJobPerm
 
diff --git a/tests/acceleration/Android.mk b/tests/acceleration/Android.mk
index 845e291..81869bf 100644
--- a/tests/acceleration/Android.mk
+++ b/tests/acceleration/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccelerationTestCases
 
diff --git a/tests/accessibility/Android.mk b/tests/accessibility/Android.mk
index d8da5efe..4cd7e92 100644
--- a/tests/accessibility/Android.mk
+++ b/tests/accessibility/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/accessibilityservice/Android.mk b/tests/accessibilityservice/Android.mk
index e0dc678..9a3bbe2 100644
--- a/tests/accessibilityservice/Android.mk
+++ b/tests/accessibilityservice/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAccessibilityServiceTestCases
 
diff --git a/tests/admin/Android.mk b/tests/admin/Android.mk
index d30cca1..24fdda3 100644
--- a/tests/admin/Android.mk
+++ b/tests/admin/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsAdminTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_INSTRUMENTATION_FOR := CtsAdminApp
 
diff --git a/tests/admin/app/Android.mk b/tests/admin/app/Android.mk
index b0e7ff5..22b5c83 100644
--- a/tests/admin/app/Android.mk
+++ b/tests/admin/app/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_PACKAGE_NAME := CtsAdminApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/app/Android.mk b/tests/app/Android.mk
index f479dca..6bd42ef 100644
--- a/tests/app/Android.mk
+++ b/tests/app/Android.mk
@@ -37,7 +37,7 @@
     $(call all-java-files-under, appSdk25/src) \
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAppTestCases
 
diff --git a/tests/app/app/Android.mk b/tests/app/app/Android.mk
index 4b6057d..191f4cc 100644
--- a/tests/app/app/Android.mk
+++ b/tests/app/app/Android.mk
@@ -37,7 +37,7 @@
               src/android/app/stubs/ISecondary.aidl
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAppTestStubs
 
diff --git a/tests/app/app2/Android.mk b/tests/app/app2/Android.mk
index 6c5ea7c..2689c30 100644
--- a/tests/app/app2/Android.mk
+++ b/tests/app/app2/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_PACKAGE_NAME := CtsAppTestStubsDifferentUid
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_DEX_PREOPT := false
 
diff --git a/tests/app/appSdk25/Android.mk b/tests/app/appSdk25/Android.mk
index e08de21..36c6d07 100644
--- a/tests/app/appSdk25/Android.mk
+++ b/tests/app/appSdk25/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_SDK_VERSION := 25
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAppTestSdk25
 
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 045301d..e718a32 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -283,13 +283,13 @@
         // Test illegal parameter
         List<RunningServiceInfo> runningServiceInfo;
         runningServiceInfo = mActivityManager.getRunningServices(-1);
-        assertTrue(runningServiceInfo.size() == 0);
+        assertTrue(runningServiceInfo.isEmpty());
 
         runningServiceInfo = mActivityManager.getRunningServices(0);
-        assertTrue(runningServiceInfo.size() == 0);
+        assertTrue(runningServiceInfo.isEmpty());
 
         runningServiceInfo = mActivityManager.getRunningServices(5);
-        assertTrue(runningServiceInfo.size() >= 0 && runningServiceInfo.size() <= 5);
+        assertTrue(runningServiceInfo.size() <= 5);
 
         Intent intent = new Intent();
         intent.setClass(mInstrumentation.getTargetContext(), MockService.class);
diff --git a/tests/aslr/Android.mk b/tests/aslr/Android.mk
index 9b4866f..2abe2a8 100644
--- a/tests/aslr/Android.mk
+++ b/tests/aslr/Android.mk
@@ -33,6 +33,6 @@
     libgtest
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/tests/autofillservice/Android.mk b/tests/autofillservice/Android.mk
index 1dbb4cc..eaf2f17 100644
--- a/tests/autofillservice/Android.mk
+++ b/tests/autofillservice/Android.mk
@@ -23,16 +23,17 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-annotations \
     compatibility-device-util \
     ctstestrunner \
     truth-prebuilt \
     ub-uiautomator \
-    testng
+    testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsAutoFillServiceTestCases
 
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 7bfb742..4bb8fa6 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -63,6 +63,8 @@
         <activity android:name=".OutOfProcessLoginActivity"
             android:process="android.autofillservice.cts.outside"/>
         <activity android:name=".FragmentContainerActivity" />
+        <activity android:name=".DuplicateIdActivity"
+            android:theme="@android:style/Theme.NoTitleBar" />
 
         <service
             android:name=".InstrumentedAutoFillService"
@@ -72,6 +74,14 @@
                 <action android:name="android.service.autofill.AutofillService" />
             </intent-filter>
         </service>
+        <service
+            android:name=".NoOpAutofillService"
+            android:label="NoOpAutofillService"
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE" >
+            <intent-filter>
+                <action android:name="android.service.autofill.AutofillService" />
+            </intent-filter>
+        </service>
     </application>
 
     <instrumentation
diff --git a/tests/autofillservice/AndroidTest.xml b/tests/autofillservice/AndroidTest.xml
index 271e573..73fffd2 100644
--- a/tests/autofillservice/AndroidTest.xml
+++ b/tests/autofillservice/AndroidTest.xml
@@ -24,6 +24,8 @@
 
   <test class="com.android.tradefed.testtype.AndroidJUnitTest">
     <option name="package" value="android.autofillservice.cts" />
+    <!-- 20x default timeout of 600sec -->
+    <option name="shell-timeout" value="12000000"/>
   </test>
 
 </configuration>
diff --git a/tests/autofillservice/res/layout/duplicate_id_layout.xml b/tests/autofillservice/res/layout/duplicate_id_layout.xml
new file mode 100644
index 0000000..a5643ea
--- /dev/null
+++ b/tests/autofillservice/res/layout/duplicate_id_layout.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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <CheckBox
+        android:id="@+id/duplicate_id"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <CheckBox
+        android:id="@+id/duplicate_id"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/autofillservice/res/layout/two_horizontal_text_fields.xml b/tests/autofillservice/res/layout/two_horizontal_text_fields.xml
new file mode 100644
index 0000000..944f926
--- /dev/null
+++ b/tests/autofillservice/res/layout/two_horizontal_text_fields.xml
@@ -0,0 +1,43 @@
+<?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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <TextView android:id="@+id/static_text"
+        android:paddingEnd="16dp"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:text="YO:"/>
+
+    <TextView android:id="@+id/first"
+        android:paddingEnd="16dp"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"/>
+
+    <TextView android:id="@+id/second"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+
+    <ImageView android:id="@+id/img"
+        android:paddingStart="16dp"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 15d1052..60d0356 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -16,16 +16,15 @@
 
 package android.autofillservice.cts;
 
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.getLoggingLevel;
 import static android.autofillservice.cts.Helper.hasAutofillFeature;
 import static android.autofillservice.cts.Helper.runShellCommand;
 import static android.autofillservice.cts.Helper.setLoggingLevel;
+import static android.autofillservice.cts.InstrumentedAutoFillService.SERVICE_NAME;
 import static android.provider.Settings.Secure.AUTOFILL_SERVICE;
 
-import static com.google.common.truth.Truth.assertWithMessage;
-
 import android.autofillservice.cts.InstrumentedAutoFillService.Replier;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -39,6 +38,8 @@
 import org.junit.Rule;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 /**
  * Base class for all other tests.
  */
@@ -46,10 +47,6 @@
 abstract class AutoFillServiceTestCase {
     private static final String TAG = "AutoFillServiceTestCase";
 
-    private static final String SERVICE_NAME =
-            InstrumentedAutoFillService.class.getPackage().getName()
-            + "/." + InstrumentedAutoFillService.class.getSimpleName();
-
     protected static UiBot sUiBot;
 
     protected static final Replier sReplier = InstrumentedAutoFillService.getReplier();
@@ -82,30 +79,16 @@
 
     @AfterClass
     public static void resetSettings() {
-        runShellCommand("settings delete secure %s", AUTOFILL_SERVICE);
-    }
-
-    @Before
-    public void disableService() {
         if (!hasAutofillFeature()) return;
 
-        if (!isServiceEnabled()) return;
-
-        final OneTimeSettingsListener observer = new OneTimeSettingsListener(getContext(),
-                AUTOFILL_SERVICE);
+        // Clean up only - no need to call disableService() because it doesn't need to fail if
+        // it's not reset.
         runShellCommand("settings delete secure %s", AUTOFILL_SERVICE);
-        observer.assertCalled();
-        assertServiceDisabled();
-
-        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(false);
     }
 
     @Before
     public void reset() {
-        destroyAllSessions();
         sReplier.reset();
-        InstrumentedAutoFillService.resetStaticState();
-        AuthenticationActivity.resetStaticState();
     }
 
     @Before
@@ -136,9 +119,18 @@
     // exceptions would mask the real cause. A better approach might be using a @Rule or some other
     // visitor pattern.
     @After
-    public void assertNoPendingRequests() {
-        sReplier.assertNumberUnhandledFillRequests(0);
-        sReplier.assertNumberUnhandledSaveRequests(0);
+    public void assertNothingIsPending() throws Exception {
+        final MultipleExceptionsCatcher catcher = new MultipleExceptionsCatcher()
+            .run(() -> sReplier.assertNumberUnhandledFillRequests(0))
+            .run(() -> sReplier.assertNumberUnhandledSaveRequests(0));
+
+        final List<Exception> replierExceptions = sReplier.getExceptions();
+        if (replierExceptions != null) {
+            for (Exception e : replierExceptions) {
+                catcher.add(e);
+            }
+        }
+        catcher.throwIfAny();
     }
 
     @After
@@ -150,66 +142,38 @@
      * Enables the {@link InstrumentedAutoFillService} for autofill for the current user.
      */
     protected void enableService() {
-        if (isServiceEnabled()) return;
+        Helper.enableAutofillService(getContext(), SERVICE_NAME);
+        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(false);
+    }
 
-        final OneTimeSettingsListener observer = new OneTimeSettingsListener(getContext(),
-                AUTOFILL_SERVICE);
-        runShellCommand("settings put secure %s %s default", AUTOFILL_SERVICE, SERVICE_NAME);
-        observer.assertCalled();
-        assertServiceEnabled();
+    /**
+     * Disables the {@link InstrumentedAutoFillService} for autofill for the current user.
+     */
+    protected void disableService() {
+        if (!hasAutofillFeature()) return;
+
+        Helper.disableAutofillService(getContext(), SERVICE_NAME);
+        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(true);
     }
 
     /**
      * Asserts that the {@link InstrumentedAutoFillService} is enabled for the default user.
      */
-    protected static void assertServiceEnabled() {
-        assertServiceStatus(true);
+    protected void assertServiceEnabled() {
+        Helper.assertAutofillServiceStatus(SERVICE_NAME, true);
     }
 
     /**
      * Asserts that the {@link InstrumentedAutoFillService} is disabled for the default user.
      */
-    protected static void assertServiceDisabled() {
-        assertServiceStatus(false);
+    protected void assertServiceDisabled() {
+        Helper.assertAutofillServiceStatus(SERVICE_NAME, false);
     }
 
-    /**
-     * Asserts that there is no session left in the service.
-     */
-    protected void assertNoDanglingSessions() {
-        final String command = "cmd autofill list sessions";
-        final String result = runShellCommand(command);
-        assertWithMessage("Dangling sessions ('%s'): %s'", command, result).that(result).isEmpty();
-    }
-
-    /**
-     * Destroys all sessions.
-     */
-    protected void destroyAllSessions() {
-        runShellCommand("cmd autofill destroy sessions");
-        assertNoDanglingSessions();
-    }
-
-    protected static Context getContext() {
-        return InstrumentationRegistry.getInstrumentation().getContext();
-    }
-
-    protected static RemoteViews createPresentation(String message) {
+    protected RemoteViews createPresentation(String message) {
         final RemoteViews presentation = new RemoteViews(getContext()
                 .getPackageName(), R.layout.list_item);
         presentation.setTextViewText(R.id.text1, message);
         return presentation;
     }
-
-    private static boolean isServiceEnabled() {
-        final String service = runShellCommand("settings get secure %s", AUTOFILL_SERVICE);
-        return SERVICE_NAME.equals(service);
-    }
-
-    private static void assertServiceStatus(boolean enabled) {
-        final String actual = runShellCommand("settings get secure %s", AUTOFILL_SERVICE);
-        final String expected = enabled ? SERVICE_NAME : "null";
-        assertWithMessage("Invalid value for secure setting %s", AUTOFILL_SERVICE)
-                .that(actual).isEqualTo(expected);
-    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
index ab1c0ea..b966078 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
@@ -18,6 +18,7 @@
 
 import static android.autofillservice.cts.FragmentContainerActivity.FRAGMENT_TAG;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -28,7 +29,6 @@
 import android.service.autofill.SaveInfo;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.test.rule.ActivityTestRule;
 import android.view.ViewGroup;
 import android.widget.EditText;
 
@@ -41,8 +41,8 @@
  */
 public class AutoFinishSessionTest extends AutoFillServiceTestCase {
     @Rule
-    public final ActivityTestRule<FragmentContainerActivity> mActivityRule =
-            new ActivityTestRule<>(FragmentContainerActivity.class);
+    public final AutofillActivityTestRule<FragmentContainerActivity> mActivityRule =
+            new AutofillActivityTestRule<>(FragmentContainerActivity.class);
     private FragmentContainerActivity mActivity;
     private EditText mEditText1;
     private EditText mEditText2;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java
new file mode 100644
index 0000000..7cf3c64
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.autofillservice.cts;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+
+/**
+ * Custom {@link ActivityTestRule} that cleans up the autofill state before the activity is
+ * launched.
+ */
+public class AutofillActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
+
+    public AutofillActivityTestRule(Class<T> activityClass) {
+        super(activityClass);
+    }
+
+    @Override
+    protected void beforeActivityLaunched() {
+        Helper.preTestCleanup();
+
+        super.beforeActivityLaunched();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
index 0ed3c86..ff18003 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
@@ -26,7 +26,6 @@
 import android.icu.util.Calendar;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.test.rule.ActivityTestRule;
 import android.view.View;
 import android.view.autofill.AutofillValue;
 import android.widget.CompoundButton;
@@ -57,8 +56,8 @@
  */
 public class AutofillValueTest extends AutoFillServiceTestCase {
     @Rule
-    public final ActivityTestRule<AllAutofillableViewsActivity> mActivityRule =
-            new ActivityTestRule<>(AllAutofillableViewsActivity.class);
+    public final AutofillActivityTestRule<AllAutofillableViewsActivity> mActivityRule =
+            new AutofillActivityTestRule<>(AllAutofillableViewsActivity.class);
 
     private AllAutofillableViewsActivity mActivity;
     private EditText mEditText;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index 07d4721..5ba68c8 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -22,10 +22,12 @@
 import android.app.assist.AssistStructure.ViewNode;
 import android.content.IntentSender;
 import android.os.Bundle;
+import android.service.autofill.CustomDescription;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillCallback;
 import android.service.autofill.FillResponse;
 import android.service.autofill.SaveInfo;
+import android.service.autofill.Validator;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.widget.RemoteViews;
@@ -58,9 +60,11 @@
     private final List<CannedDataset> mDatasets;
     private final String mFailureMessage;
     private final int mSaveType;
+    private final Validator mValidator;
     private final String[] mRequiredSavableIds;
     private final String[] mOptionalSavableIds;
     private final String mSaveDescription;
+    private final CustomDescription mCustomDescription;
     private final Bundle mExtras;
     private final RemoteViews mPresentation;
     private final IntentSender mAuthentication;
@@ -74,9 +78,11 @@
         mResponseType = builder.mResponseType;
         mDatasets = builder.mDatasets;
         mFailureMessage = builder.mFailureMessage;
+        mValidator = builder.mValidator;
         mRequiredSavableIds = builder.mRequiredSavableIds;
         mOptionalSavableIds = builder.mOptionalSavableIds;
         mSaveDescription = builder.mSaveDescription;
+        mCustomDescription = builder.mCustomDescription;
         mSaveType = builder.mSaveType;
         mExtras = builder.mExtras;
         mPresentation = builder.mPresentation;
@@ -124,11 +130,17 @@
             }
         }
         if (mRequiredSavableIds != null) {
-            final SaveInfo.Builder saveInfo = new SaveInfo.Builder(mSaveType,
-                    getAutofillIds(nodeResolver, mRequiredSavableIds));
+            final SaveInfo.Builder saveInfo =
+                    mRequiredSavableIds == null || mRequiredSavableIds.length == 0
+                        ? new SaveInfo.Builder(mSaveType)
+                            : new SaveInfo.Builder(mSaveType,
+                                    getAutofillIds(nodeResolver, mRequiredSavableIds));
 
             saveInfo.setFlags(mFlags);
 
+            if (mValidator != null) {
+                saveInfo.setValidator(mValidator);
+            }
             if (mOptionalSavableIds != null) {
                 saveInfo.setOptionalIds(getAutofillIds(nodeResolver, mOptionalSavableIds));
             }
@@ -136,6 +148,10 @@
                 saveInfo.setDescription(mSaveDescription);
             }
             saveInfo.setNegativeAction(mNegativeActionStyle, mNegativeActionListener);
+
+            if (mCustomDescription != null) {
+                saveInfo.setCustomDescription(mCustomDescription);
+            }
             builder.setSaveInfo(saveInfo.build());
         }
         if (mIgnoredIds != null) {
@@ -159,6 +175,7 @@
                 + ", flags=" + mFlags
                 + ", failureMessage=" + mFailureMessage
                 + ", saveDescription=" + mSaveDescription
+                + ", mCustomDescription=" + mCustomDescription
                 + ", hasPresentation=" + (mPresentation != null)
                 + ", hasAuthentication=" + (mAuthentication != null)
                 + ", authenticationIds=" + Arrays.toString(mAuthenticationIds)
@@ -176,9 +193,11 @@
         private final List<CannedDataset> mDatasets = new ArrayList<>();
         private final ResponseType mResponseType;
         private String mFailureMessage;
+        private Validator mValidator;
         private String[] mRequiredSavableIds;
         private String[] mOptionalSavableIds;
         private String mSaveDescription;
+        public CustomDescription mCustomDescription;
         public int mSaveType = -1;
         private Bundle mExtras;
         private RemoteViews mPresentation;
@@ -204,6 +223,14 @@
         }
 
         /**
+         * Sets the validator for this request
+         */
+        public Builder setValidator(Validator validator) {
+            mValidator = validator;
+            return this;
+        }
+
+        /**
          * Sets the required savable ids based on they {@code resourceId}.
          */
         public Builder setRequiredSavableIds(int type, String... ids) {
@@ -234,6 +261,14 @@
         }
 
         /**
+         * Sets the description passed to the {@link SaveInfo}.
+         */
+        public Builder setCustomDescription(CustomDescription description) {
+            mCustomDescription = description;
+            return this;
+        }
+
+        /**
          * Sets the extra passed to {@link
          * android.service.autofill.FillResponse.Builder#setClientState(Bundle)}.
          */
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
new file mode 100644
index 0000000..39e7c22
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.service.autofill.CharSequenceTransformation;
+import android.service.autofill.ValueFinder;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.autofill.AutofillId;
+import android.widget.RemoteViews;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class CharSequenceTransformationTest {
+
+    @Test
+    public void testAllNullBuilder() {
+        assertThrows(NullPointerException.class,
+                () ->  new CharSequenceTransformation.Builder(null, null, null));
+    }
+
+    @Test
+    public void testNullAutofillIdBuilder() {
+        assertThrows(NullPointerException.class,
+                () -> new CharSequenceTransformation.Builder(null, Pattern.compile(""), ""));
+    }
+
+    @Test
+    public void testNullRegexBuilder() {
+        assertThrows(NullPointerException.class,
+                () -> new CharSequenceTransformation.Builder(new AutofillId(1), null, ""));
+    }
+
+    @Test
+    public void testNullSubstBuilder() {
+        assertThrows(NullPointerException.class,
+                () -> new CharSequenceTransformation.Builder(new AutofillId(1), Pattern.compile(""),
+                        null));
+    }
+
+    @Test
+    public void testBadSubst() {
+        AutofillId id1 = new AutofillId(1);
+        AutofillId id2 = new AutofillId(2);
+        AutofillId id3 = new AutofillId(3);
+        AutofillId id4 = new AutofillId(4);
+
+        CharSequenceTransformation.Builder b = new CharSequenceTransformation.Builder(id1,
+                Pattern.compile("(.)"), "1=$1");
+
+        // bad subst: The regex has no capture groups
+        b.addField(id2, Pattern.compile("."), "2=$1");
+
+        // bad subst: The regex does not have enough capture groups
+        b.addField(id3, Pattern.compile("(.)"), "3=$2");
+
+        b.addField(id4, Pattern.compile("(.)"), "4=$1");
+
+        CharSequenceTransformation trans = b.build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(id1)).thenReturn("a");
+        when(finder.findByAutofillId(id2)).thenReturn("b");
+        when(finder.findByAutofillId(id3)).thenReturn("c");
+        when(finder.findByAutofillId(id4)).thenReturn("d");
+
+        assertThrows(ArrayIndexOutOfBoundsException.class, () -> trans.apply(finder, template, 0));
+
+        // fail one, fail all
+        verify(template, never()).setCharSequence(eq(0), any(), any());
+    }
+
+    @Test
+    public void testUnknownField() throws Exception {
+        AutofillId id1 = new AutofillId(1);
+        AutofillId id2 = new AutofillId(2);
+        AutofillId unknownId = new AutofillId(42);
+
+        CharSequenceTransformation.Builder b = new CharSequenceTransformation.Builder(id1,
+                Pattern.compile(".*"), "1");
+
+        // bad subst: The field will not be found
+        b.addField(unknownId, Pattern.compile(".*"), "unknown");
+
+        b.addField(id2, Pattern.compile(".*"), "2");
+
+        CharSequenceTransformation trans = b.build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(id1)).thenReturn("1");
+        when(finder.findByAutofillId(id2)).thenReturn("2");
+        when(finder.findByAutofillId(unknownId)).thenReturn(null);
+
+        trans.apply(finder, template, 0);
+
+        // if a view cannot be found, nothing is not, not even partial results
+        verify(template, never()).setCharSequence(eq(0), any(), any());
+    }
+
+    @Test
+    public void testCreditCardObfuscator() throws Exception {
+        AutofillId creditCardFieldId = new AutofillId(1);
+        CharSequenceTransformation trans = new CharSequenceTransformation
+                .Builder(creditCardFieldId,
+                        Pattern.compile("^\\s*\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?(\\d{4})\\s*$"),
+                        "...$1")
+                .build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(creditCardFieldId)).thenReturn("1234 5678 9012 3456");
+
+        trans.apply(finder, template, 0);
+
+        verify(template).setCharSequence(eq(0), any(), argThat(new CharSequenceMatcher("...3456")));
+    }
+
+    @Test
+    public void userNameObfuscator() throws Exception {
+        AutofillId userNameFieldId = new AutofillId(1);
+        AutofillId passwordFieldId = new AutofillId(2);
+        CharSequenceTransformation trans = new CharSequenceTransformation
+                .Builder(userNameFieldId, Pattern.compile("(.*)"), "$1")
+                .addField(passwordFieldId, Pattern.compile(".*(..)$"), "/..$1")
+                .build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(userNameFieldId)).thenReturn("myUserName");
+        when(finder.findByAutofillId(passwordFieldId)).thenReturn("myPassword");
+
+        trans.apply(finder, template, 0);
+
+        verify(template).setCharSequence(eq(0), any(),
+                argThat(new CharSequenceMatcher("myUserName/..rd")));
+    }
+
+    static class CharSequenceMatcher implements ArgumentMatcher<CharSequence> {
+        private final CharSequence mExpected;
+
+        public CharSequenceMatcher(CharSequence expected) {
+            mExpected = expected;
+        }
+
+        @Override
+        public boolean matches(CharSequence actual) {
+            return actual.toString().equals(mExpected.toString());
+        }
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
index 0b8d938..f5e7f87 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
@@ -80,13 +80,13 @@
 
         setContentView(getContentView());
 
-        mCcNumber = (EditText) findViewById(R.id.cc_number);
-        mCcExpiration = (Spinner) findViewById(R.id.cc_expiration);
-        mAddress = (RadioGroup) findViewById(R.id.address);
-        mHomeAddress = (RadioButton ) findViewById(R.id.home_address);
-        mSaveCc = (CheckBox) findViewById(R.id.save_cc);
-        mBuyButton = (Button) findViewById(R.id.buy);
-        mClearButton = (Button) findViewById(R.id.clear);
+        mCcNumber = findViewById(R.id.cc_number);
+        mCcExpiration = findViewById(R.id.cc_expiration);
+        mAddress = findViewById(R.id.address);
+        mHomeAddress = findViewById(R.id.home_address);
+        mSaveCc = findViewById(R.id.save_cc);
+        mBuyButton = findViewById(R.id.buy);
+        mClearButton = findViewById(R.id.clear);
 
         mCcExpirationAdapter = createFromResource(this,
                 R.array.cc_expiration_values, android.R.layout.simple_spinner_item);
@@ -203,6 +203,18 @@
                 .that(called).isTrue();
     }
 
+    EditText getCcNumber() {
+        return mCcNumber;
+    }
+
+    Spinner getCcExpiration() {
+        return mCcExpiration;
+    }
+
+    ArrayAdapter<CharSequence> getCcExpirationAdapter() {
+        return mCcExpirationAdapter;
+    }
+
     /**
      * Holder for the expected auto-fill values.
      */
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index c3809a0..7d68e58 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -31,6 +31,7 @@
 import static android.autofillservice.cts.Helper.assertToggleIsSanitized;
 import static android.autofillservice.cts.Helper.assertToggleValue;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
 import static android.view.View.AUTOFILL_TYPE_LIST;
 
@@ -41,8 +42,12 @@
 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.support.test.rule.ActivityTestRule;
+import android.service.autofill.CharSequenceTransformation;
+import android.service.autofill.CustomDescription;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
 import android.widget.ArrayAdapter;
+import android.widget.RemoteViews;
 import android.widget.Spinner;
 
 import org.junit.After;
@@ -51,6 +56,7 @@
 import org.junit.Test;
 
 import java.util.Arrays;
+import java.util.regex.Pattern;
 
 /**
  * Test case for an activity containing non-TextField views.
@@ -58,8 +64,8 @@
 public class CheckoutActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<CheckoutActivity> mActivityRule =
-        new ActivityTestRule<CheckoutActivity>(CheckoutActivity.class);
+    public final AutofillActivityTestRule<CheckoutActivity> mActivityRule =
+        new AutofillActivityTestRule<CheckoutActivity>(CheckoutActivity.class);
 
     private CheckoutActivity mActivity;
 
@@ -242,4 +248,114 @@
         assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_WORK_ADDRESS), true);
         assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_SAVE_CC), false);
     }
+
+    /**
+     * Tests that a spinner can be used on custom save descriptions.
+     */
+    @Test
+    public void testCustomizedSaveUi() throws Exception {
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        final String packageName = getContext().getPackageName();
+
+        final RemoteViews presentation = new RemoteViews(packageName,
+                R.layout.two_horizontal_text_fields);
+        final CharSequenceTransformation trans1 = new CharSequenceTransformation
+                .Builder(mActivity.getCcNumber().getAutofillId(), Pattern.compile("(.*)"), "$1")
+                .build();
+        final CharSequenceTransformation trans2 = new CharSequenceTransformation
+                .Builder(mActivity.getCcExpiration().getAutofillId(), Pattern.compile("(.*)"), "$1")
+                .build();
+        final CustomDescription customDescription = new CustomDescription.Builder(presentation)
+                .addChild(R.id.first, trans1)
+                .addChild(R.id.second, trans2)
+                .build();
+
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_CREDIT_CARD, ID_CC_NUMBER, ID_CC_EXPIRATION)
+                .setCustomDescription(customDescription)
+                .build());
+
+        // Dynamically change view contents
+        mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TOMORROW, true));
+
+        // Trigger auto-fill.
+        mActivity.onCcNumber((v) -> v.requestFocus());
+        sReplier.getNextFillRequest();
+
+        // Trigger save.
+        mActivity.onCcNumber((v) -> v.setText("4815162342"));
+        mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TODAY));
+        mActivity.tapBuy();
+
+        // First make sure the UI is shown...
+        final UiObject2 saveUi = sUiBot.assertSaveShowing(SAVE_DATA_TYPE_CREDIT_CARD);
+
+        // Then make sure it does have the custom views on it...
+        final UiObject2 staticText = saveUi.findObject(By.res(packageName, "static_text"));
+        assertThat(staticText).isNotNull();
+        assertThat(staticText.getText()).isEqualTo("YO:");
+
+        final UiObject2 number = saveUi.findObject(By.res(packageName, "first"));
+        assertThat(number).isNotNull();
+        assertThat(number.getText()).isEqualTo("4815162342");
+
+        final UiObject2 expiration = saveUi.findObject(By.res(packageName, "second"));
+        assertThat(expiration).isNotNull();
+        assertThat(expiration.getText()).isEqualTo("today");
+    }
+
+    /**
+     * Tests that a custom save description is ignored when the selected spinner element is not
+     * available in the autofill options.
+     */
+    @Test
+    public void testCustomizedSaveUiWhenListResolutionFails() throws Exception {
+        // Set service.
+        enableService();
+
+        // Change spinner to return just one item so the transformation throws an exception when
+        // fetching it.
+        mActivity.getCcExpirationAdapter().setAutofillOptions("D'OH!");
+
+        // Set expectations.
+        final String packageName = getContext().getPackageName();
+        final RemoteViews presentation = new RemoteViews(packageName,
+                R.layout.two_horizontal_text_fields);
+        final CharSequenceTransformation trans1 = new CharSequenceTransformation
+                .Builder(mActivity.getCcNumber().getAutofillId(), Pattern.compile("(.*)"), "$1")
+                .build();
+        final CharSequenceTransformation trans2 = new CharSequenceTransformation
+                .Builder(mActivity.getCcExpiration().getAutofillId(), Pattern.compile("(.*)"), "$1")
+                .build();
+        final CustomDescription customDescription = new CustomDescription.Builder(presentation)
+                .addChild(R.id.first, trans1)
+                .addChild(R.id.second, trans2)
+                .build();
+
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_CREDIT_CARD, ID_CC_NUMBER, ID_CC_EXPIRATION)
+                .setCustomDescription(customDescription)
+                .build());
+
+        // Dynamically change view contents
+        mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TOMORROW, true));
+
+        // Trigger auto-fill.
+        mActivity.onCcNumber((v) -> v.requestFocus());
+        sReplier.getNextFillRequest();
+
+        // Trigger save.
+        mActivity.onCcNumber((v) -> v.setText("4815162342"));
+        mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TODAY));
+        mActivity.tapBuy();
+
+        // First make sure the UI is shown...
+        final UiObject2 saveUi = sUiBot.assertSaveShowing(SAVE_DATA_TYPE_CREDIT_CARD);
+
+        // Then make sure it does not have the custom views on it...
+        assertThat(saveUi.findObject(By.res(packageName, "static_text"))).isNull();
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
new file mode 100644
index 0000000..05cccd7
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.assertNoDanglingSessions;
+import static android.autofillservice.cts.Helper.getContext;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.service.autofill.CharSequenceTransformation;
+import android.service.autofill.CustomDescription;
+import android.service.autofill.ImageTransformation;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.widget.RemoteViews;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.function.BiFunction;
+import java.util.regex.Pattern;
+
+public class CustomDescriptionTest extends AutoFillServiceTestCase {
+    @Rule
+    public final AutofillActivityTestRule<LoginActivity> mActivityRule =
+        new AutofillActivityTestRule<>(LoginActivity.class);
+
+    private LoginActivity mActivity;
+    private String mPackageName;
+
+    @Before
+    public void setActivity() {
+        mActivity = mActivityRule.getActivity();
+        mPackageName = InstrumentationRegistry.getInstrumentation().getContext().getPackageName();
+    }
+
+    @After
+    public void finishWelcomeActivity() {
+        WelcomeActivity.finishIt();
+    }
+
+    /**
+     * Base test
+     *
+     * @param descriptionBuilder method to build a custom description
+     * @param uiVerifier         Ran when the custom description is shown
+     */
+    private void testCustomDescription(
+            @NonNull BiFunction<AutofillId, AutofillId, CustomDescription> descriptionBuilder,
+            @Nullable Runnable uiVerifier) throws Exception {
+        enableService();
+
+        AutofillId usernameId = mActivity.getUsername().getAutofillId();
+        AutofillId passwordId = mActivity.getPassword().getAutofillId();
+
+        // Set response with custom description
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_USERNAME, ID_PASSWORD)
+                .setCustomDescription(descriptionBuilder.apply(usernameId, passwordId))
+                .build());
+
+        // Trigger auto-fill with custom description
+        mActivity.onPassword(View::requestFocus);
+
+        // Wait for onFill() before proceeding.
+        sReplier.getNextFillRequest();
+
+        // Trigger save.
+        mActivity.onUsername((v) -> v.setText("usernm"));
+        mActivity.onPassword((v) -> v.setText("passwd"));
+        mActivity.tapLogin();
+
+        if (uiVerifier != null) {
+            uiVerifier.run();
+        }
+
+        sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+        sReplier.getNextSaveRequest();
+
+        assertNoDanglingSessions();
+    }
+
+    @Test
+    public void validTransformation() throws Exception {
+        testCustomDescription((usernameId, passwordId) -> {
+            RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                    R.layout.two_horizontal_text_fields);
+
+            CharSequenceTransformation trans1 = new CharSequenceTransformation
+                    .Builder(usernameId, Pattern.compile("(.*)"), "$1")
+                    .addField(passwordId, Pattern.compile(".*(..)"), "..$1")
+                    .build();
+            ImageTransformation trans2 = new ImageTransformation
+                    .Builder(usernameId, Pattern.compile(".*"),
+                    R.drawable.android).build();
+
+            return new CustomDescription.Builder(presentation)
+                    .addChild(R.id.first, trans1)
+                    .addChild(R.id.img, trans2)
+                    .build();
+        }, () -> assertSaveUiWithCustomDescriptionIsShown("usernm..wd"));
+    }
+
+    @Test
+    public void badImageTransformation() throws Exception {
+        testCustomDescription((usernameId, passwordId) -> {
+            RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                    R.layout.two_horizontal_text_fields);
+
+            ImageTransformation trans = new ImageTransformation
+                    .Builder(usernameId, Pattern.compile(".*"), 1)
+                    .build();
+
+            return new CustomDescription.Builder(presentation)
+                    .addChild(R.id.img, trans)
+                    .build();
+        }, () -> assertSaveUiWithCustomDescriptionIsShown() );
+    }
+
+    @Test
+    public void unusedImageTransformation() throws Exception {
+        testCustomDescription((usernameId, passwordId) -> {
+            RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                    R.layout.two_horizontal_text_fields);
+
+            ImageTransformation trans = new ImageTransformation
+                    .Builder(usernameId, Pattern.compile("invalid"), R.drawable.android)
+                    .build();
+
+            return new CustomDescription.Builder(presentation)
+                    .addChild(R.id.img, trans)
+                    .build();
+        }, () -> assertSaveUiWithCustomDescriptionIsShown());
+    }
+
+    @Test
+    public void applyImageTransformationToTextView() throws Exception {
+        testCustomDescription((usernameId, passwordId) -> {
+            RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                    R.layout.two_horizontal_text_fields);
+
+            ImageTransformation trans = new ImageTransformation
+                    .Builder(usernameId, Pattern.compile(".*"), R.drawable.android)
+                    .build();
+
+            return new CustomDescription.Builder(presentation)
+                    .addChild(R.id.first, trans)
+                    .build();
+        }, () -> assertSaveUiWithoutCustomDescriptionIsShown());
+    }
+
+    @Test
+    public void failFirstFailAll() throws Exception {
+        testCustomDescription((usernameId, passwordId) -> {
+            RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                    R.layout.two_horizontal_text_fields);
+
+            CharSequenceTransformation trans = new CharSequenceTransformation
+                    .Builder(usernameId, Pattern.compile("(.*)"), "$42")
+                    .addField(passwordId, Pattern.compile(".*(..)"), "..$1")
+                    .build();
+
+            return new CustomDescription.Builder(presentation)
+                    .addChild(R.id.first, trans)
+                    .build();
+        }, () -> assertSaveUiWithoutCustomDescriptionIsShown());
+    }
+
+    @Test
+    public void failSecondFailAll() throws Exception {
+        testCustomDescription((usernameId, passwordId) -> {
+            RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                    R.layout.two_horizontal_text_fields);
+
+            CharSequenceTransformation trans = new CharSequenceTransformation
+                    .Builder(usernameId, Pattern.compile("(.*)"), "$1")
+                    .addField(passwordId, Pattern.compile(".*(..)"), "..$42")
+                    .build();
+
+            return new CustomDescription.Builder(presentation)
+                    .addChild(R.id.first, trans)
+                    .build();
+        }, () -> assertSaveUiWithoutCustomDescriptionIsShown());
+    }
+
+    @Test
+    public void applyCharSequenceTransformationToImageView() throws Exception {
+        testCustomDescription((usernameId, passwordId) -> {
+            RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                    R.layout.two_horizontal_text_fields);
+
+            CharSequenceTransformation trans = new CharSequenceTransformation
+                    .Builder(usernameId, Pattern.compile("(.*)"), "$1")
+                    .build();
+
+            return new CustomDescription.Builder(presentation)
+                    .addChild(R.id.img, trans)
+                    .build();
+        }, () -> assertSaveUiWithoutCustomDescriptionIsShown());
+    }
+
+    private void assertSaveUiWithoutCustomDescriptionIsShown() {
+        // First make sure the UI is shown...
+        final UiObject2 saveUi = sUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+        // Then make sure it does not have the custom view on it.
+        assertWithMessage("found static_text on SaveUI (%s)", sUiBot.getChildrenAsText(saveUi))
+            .that(saveUi.findObject(By.res(mPackageName, "static_text"))).isNull();
+    }
+
+    private UiObject2 assertSaveUiWithCustomDescriptionIsShown() {
+        // First make sure the UI is shown...
+        final UiObject2 saveUi = sUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+        // Then make sure it does have the custom view on it...
+        final UiObject2 staticText = saveUi.findObject(By.res(mPackageName, "static_text"));
+        assertThat(staticText).isNotNull();
+        assertThat(staticText.getText()).isEqualTo("YO:");
+
+        return saveUi;
+    }
+
+    private void assertSaveUiWithCustomDescriptionIsShown(String expectedText) {
+        final UiObject2 saveUi = assertSaveUiWithCustomDescriptionIsShown();
+        assertWithMessage("didn't find '%s' on SaveUI (%s)", expectedText,
+                sUiBot.getChildrenAsText(saveUi))
+                        .that(saveUi.findObject(By.text(expectedText))).isNotNull();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
index a51a00c..40c11d3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class DatePickerCalendarActivityTest extends DatePickerTestCase<DatePickerCalendarActivity> {
 
     @Rule
-    public final ActivityTestRule<DatePickerCalendarActivity> mActivityRule =
-        new ActivityTestRule<DatePickerCalendarActivity>(DatePickerCalendarActivity.class);
+    public final AutofillActivityTestRule<DatePickerCalendarActivity> mActivityRule =
+        new AutofillActivityTestRule<DatePickerCalendarActivity>(DatePickerCalendarActivity.class);
 
     @Override
     protected DatePickerCalendarActivity getDatePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
index 10851cd..0497f87 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class DatePickerSpinnerActivityTest extends DatePickerTestCase<DatePickerSpinnerActivity> {
 
     @Rule
-    public final ActivityTestRule<DatePickerSpinnerActivity> mActivityRule =
-        new ActivityTestRule<DatePickerSpinnerActivity>(DatePickerSpinnerActivity.class);
+    public final AutofillActivityTestRule<DatePickerSpinnerActivity> mActivityRule =
+        new AutofillActivityTestRule<DatePickerSpinnerActivity>(DatePickerSpinnerActivity.class);
 
     @Override
     protected DatePickerSpinnerActivity getDatePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DuplicateIdActivity.java b/tests/autofillservice/src/android/autofillservice/cts/DuplicateIdActivity.java
new file mode 100644
index 0000000..31ac8f7
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/DuplicateIdActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import android.os.Bundle;
+import android.util.Log;
+
+public class DuplicateIdActivity extends AbstractAutoFillActivity {
+    private static final String LOG_TAG = DuplicateIdActivity.class.getSimpleName();
+
+    static final String DUPLICATE_ID = "duplicate_id";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState != null) {
+            Log.i(LOG_TAG, "onCreate(" + savedInstanceState + ")");
+        }
+
+        setContentView(R.layout.duplicate_id_layout);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DuplicateIdActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DuplicateIdActivityTest.java
new file mode 100644
index 0000000..a112b88
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/DuplicateIdActivityTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
+import static android.autofillservice.cts.DuplicateIdActivity.DUPLICATE_ID;
+import static android.autofillservice.cts.Helper.runShellCommand;
+import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilConnected;
+import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilDisconnected;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.assist.AssistStructure;
+import android.util.Log;
+import android.view.autofill.AutofillId;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * This is the test case covering most scenarios - other test cases will cover characteristics
+ * specific to that test's activity (for example, custom views).
+ */
+public class DuplicateIdActivityTest extends AutoFillServiceTestCase {
+    private static final String LOG_TAG = DuplicateIdActivityTest.class.getSimpleName();
+    @Rule
+    public final AutofillActivityTestRule<DuplicateIdActivity> mActivityRule = new AutofillActivityTestRule<>(
+            DuplicateIdActivity.class);
+
+    private DuplicateIdActivity mActivity;
+
+    @Before
+    public void setup() {
+        Helper.disableAutoRotation();
+        Helper.setOrientation(0);
+
+        mActivity = mActivityRule.getActivity();
+    }
+
+    @After
+    public void teardown() {
+        mActivity.finish();
+
+        Helper.allowAutoRotation();
+    }
+
+    /**
+     * Find the views that are tested from the structure in the request
+     *
+     * @param request The request
+     *
+     * @return An array containing the two tested views
+     */
+    private AssistStructure.ViewNode[] findViews(InstrumentedAutoFillService.FillRequest request) {
+        assertThat(request.structure.getWindowNodeCount()).isEqualTo(1);
+        AssistStructure.WindowNode windowNode = request.structure.getWindowNodeAt(0);
+
+        AssistStructure.ViewNode rootNode = windowNode.getRootViewNode();
+
+        assertThat(rootNode.getChildCount()).isEqualTo(2);
+        return new AssistStructure.ViewNode[]{rootNode.getChildAt(0), rootNode.getChildAt(1)};
+    }
+
+    @Test
+    public void testDoNotRestoreDuplicateAutofillIds() throws Exception {
+        enableService();
+
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(DUPLICATE_ID, "value")
+                        .setPresentation(createPresentation("dataset"))
+                        .build())
+                .build());
+
+        // Select field to start autofill
+        runShellCommand("input keyevent KEYCODE_TAB");
+
+        waitUntilConnected();
+        InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest();
+
+        AssistStructure.ViewNode[] views = findViews(request);
+        AssistStructure.ViewNode view1 = views[0];
+        AssistStructure.ViewNode view2 = views[1];
+        AutofillId id1 = view1.getAutofillId();
+        AutofillId id2 = view2.getAutofillId();
+
+        Log.i(LOG_TAG, "view1=" + id1);
+        Log.i(LOG_TAG, "view2=" + id2);
+
+        // Both checkboxes use the same id
+        assertThat(view1.getId()).isEqualTo(view2.getId());
+
+        // They got different autofill ids though
+        assertThat(id1).isNotEqualTo(id2);
+
+        sReplier.addResponse(NO_RESPONSE);
+
+        // Force rotation to force onDestroy->onCreate cycle
+        Helper.setOrientation(1);
+
+        // Select other field to trigger new partition
+        runShellCommand("input keyevent KEYCODE_TAB");
+
+        request = sReplier.getNextFillRequest();
+
+        views = findViews(request);
+        AutofillId recreatedId1 = views[0].getAutofillId();
+        AutofillId recreatedId2 = views[1].getAutofillId();
+
+        Log.i(LOG_TAG, "restored view1=" + recreatedId1);
+        Log.i(LOG_TAG, "restored view2=" + recreatedId2);
+
+        // For the restoring logic the two views are the same. Hence it might happen that the first
+        // view is restored with the id of the second view or the other way round.
+        // We just need
+        // - to restore as many views as we can (i.e. one)
+        // - make sure the autofill ids are still unique after
+        boolean view1WasRestored = (recreatedId1.equals(id1) || recreatedId1.equals(id2));
+        boolean view2WasRestored = (recreatedId2.equals(id1) || recreatedId2.equals(id2));
+
+        // One id was restored
+        assertThat(view1WasRestored || view2WasRestored).isTrue();
+
+        // The views still have different autofill ids
+        assertThat(recreatedId1).isNotEqualTo(recreatedId2);
+
+        waitUntilDisconnected();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
index a2edf4d..b2dd1d4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
@@ -18,18 +18,18 @@
 import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
 import static android.autofillservice.cts.FatActivity.ID_CAPTCHA;
 import static android.autofillservice.cts.FatActivity.ID_IMAGE;
-import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_IMAGE;
-import static android.autofillservice.cts.FatActivity.ID_INPUT;
-import static android.autofillservice.cts.FatActivity.ID_INPUT_CONTAINER;
 import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS;
 import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_CHILD;
 import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_GRAND_CHILD;
-import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS;
-import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_CHILD;
-import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD;
+import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_IMAGE;
+import static android.autofillservice.cts.FatActivity.ID_INPUT;
+import static android.autofillservice.cts.FatActivity.ID_INPUT_CONTAINER;
 import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS;
 import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_CHILD;
 import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_GRAND_CHILD;
+import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS;
+import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_CHILD;
+import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD;
 import static android.autofillservice.cts.Helper.assertNumberOfChildren;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
 import static android.autofillservice.cts.Helper.findNodeByText;
@@ -38,7 +38,6 @@
 
 import android.app.assist.AssistStructure.ViewNode;
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -50,8 +49,8 @@
 public class FatActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<FatActivity> mActivityRule =
-        new ActivityTestRule<FatActivity>(FatActivity.class);
+    public final AutofillActivityTestRule<FatActivity> mActivityRule =
+        new AutofillActivityTestRule<FatActivity>(FatActivity.class);
 
     private FatActivity mFatActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index cf383a1..c490913 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -16,8 +16,11 @@
 
 package android.autofillservice.cts;
 
+import static android.autofillservice.cts.Helper.hasAutofillFeature;
 import static android.autofillservice.cts.Helper.runShellCommand;
+import static android.autofillservice.cts.InstrumentedAutoFillService.SERVICE_NAME;
 import static android.provider.Settings.Secure.AUTOFILL_SERVICE;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -51,9 +54,6 @@
 
     private static final String TAG = "AutoFillCtsHelper";
 
-    // TODO: should static import Settings.Secure instead, but that's not a @TestApi
-    private static String USER_SETUP_COMPLETE = "user_setup_complete";
-
     static final boolean VERBOSE = false;
 
     static final String ID_USERNAME_LABEL = "username_label";
@@ -696,6 +696,92 @@
         runShellCommand("cmd autofill set log_level %s", level);
     }
 
+    /**
+     * Uses Settings to enable the given autofill service for the default user, and checks the
+     * value was properly check, throwing an exception if it was not.
+     */
+    public static void enableAutofillService(Context context, String serviceName) {
+        if (isAutofillServiceEnabled(serviceName)) return;
+
+        final OneTimeSettingsListener observer = new OneTimeSettingsListener(context,
+                AUTOFILL_SERVICE);
+        runShellCommand("settings put secure %s %s default", AUTOFILL_SERVICE, serviceName);
+        observer.assertCalled();
+        assertAutofillServiceStatus(serviceName, true);
+    }
+
+    /**
+     * Uses Settings to disable the given autofill service for the default user, and checks the
+     * value was properly check, throwing an exception if it was not.
+     */
+    public static void disableAutofillService(Context context, String serviceName) {
+        if (!isAutofillServiceEnabled(serviceName)) return;
+
+        final OneTimeSettingsListener observer = new OneTimeSettingsListener(context,
+                AUTOFILL_SERVICE);
+        runShellCommand("settings delete secure %s", AUTOFILL_SERVICE);
+        observer.assertCalled();
+        assertAutofillServiceStatus(serviceName, false);
+    }
+
+    /**
+     * Checks whether the given service is set as the autofill service for the default user.
+     */
+    public static boolean isAutofillServiceEnabled(String serviceName) {
+        final String actualName = runShellCommand("settings get secure %s", AUTOFILL_SERVICE);
+        return serviceName.equals(actualName);
+    }
+
+    /**
+     * Asserts whether the given service is enabled as the autofill service for the default user.
+     */
+    public static void assertAutofillServiceStatus(String serviceName, boolean enabled) {
+        final String actual = runShellCommand("settings get secure %s", AUTOFILL_SERVICE);
+        final String expected = enabled ? serviceName : "null";
+        assertWithMessage("Invalid value for secure setting %s", AUTOFILL_SERVICE)
+                .that(actual).isEqualTo(expected);
+    }
+
+    /**
+     * Asserts that there is no session left in the service.
+     */
+    public static void assertNoDanglingSessions() {
+        final String command = "cmd autofill list sessions";
+        final String result = runShellCommand(command);
+        assertWithMessage("Dangling sessions ('%s'): %s'", command, result).that(result).isEmpty();
+    }
+
+    /**
+     * Destroys all sessions.
+     */
+    public static void destroyAllSessions() {
+        runShellCommand("cmd autofill destroy sessions");
+        assertNoDanglingSessions();
+    }
+
+    /**
+     * Gets the instrumentation context.
+     */
+    public static Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    /**
+     * Cleans up the autofill state; should be called before pretty much any test.
+     */
+    public static void preTestCleanup() {
+        if (!hasAutofillFeature()) return;
+
+        Log.d(TAG, "preTestCleanup()");
+
+        disableAutofillService(getContext(), SERVICE_NAME);
+        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(true);
+
+        destroyAllSessions();
+        InstrumentedAutoFillService.resetStaticState();
+        AuthenticationActivity.resetStaticState();
+    }
+
     private Helper() {
     }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
new file mode 100644
index 0000000..e96df05
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.only;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.service.autofill.ImageTransformation;
+import android.service.autofill.ValueFinder;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.autofill.AutofillId;
+import android.widget.RemoteViews;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class ImageTransformationTest {
+
+    @Test
+    public void testAllNullBuilder() {
+        assertThrows(NullPointerException.class,
+                () ->  new ImageTransformation.Builder(null, null, 0));
+    }
+
+    @Test
+    public void testNullAutofillIdBuilder() {
+        assertThrows(NullPointerException.class,
+                () ->  new ImageTransformation.Builder(null, Pattern.compile(""), 1));
+    }
+
+    @Test
+    public void testNullRegexBuilder() {
+        assertThrows(NullPointerException.class,
+                () ->  new ImageTransformation.Builder(new AutofillId(1), null, 1));
+    }
+
+    @Test
+    public void testNullSubstBuilder() {
+        assertThrows(IllegalArgumentException.class,
+                () ->  new ImageTransformation.Builder(new AutofillId(1), Pattern.compile(""), 0));
+    }
+
+    @Test
+    public void fieldCannotBeFound() throws Exception {
+        AutofillId unknownId = new AutofillId(42);
+
+        ImageTransformation trans = new ImageTransformation
+                .Builder(unknownId, Pattern.compile("val"), 1)
+                .build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(unknownId)).thenReturn(null);
+
+        trans.apply(finder, template, 0);
+
+        // if a view cannot be found, nothing is set
+        verify(template, never()).setImageViewResource(anyInt(), anyInt());
+    }
+
+    @Test
+    public void theOneOptionsMatches() throws Exception {
+        AutofillId id = new AutofillId(1);
+        ImageTransformation trans = new ImageTransformation
+                .Builder(id, Pattern.compile(".*"), 42)
+                .build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(id)).thenReturn("val");
+
+        trans.apply(finder, template, 0);
+
+        verify(template).setImageViewResource(0, 42);
+    }
+
+    @Test
+    public void noOptionsMatches() throws Exception {
+        AutofillId id = new AutofillId(1);
+        ImageTransformation trans = new ImageTransformation
+                .Builder(id, Pattern.compile("val"), 42)
+                .build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(id)).thenReturn("bad-val");
+
+        trans.apply(finder, template, 0);
+
+        verify(template, never()).setImageViewResource(anyInt(), anyInt());
+    }
+
+    @Test
+    public void multipleOptionsOneMatches() throws Exception {
+        AutofillId id = new AutofillId(1);
+        ImageTransformation trans = new ImageTransformation
+                .Builder(id, Pattern.compile(".*1"), 1)
+                .addOption(Pattern.compile(".*2"), 2)
+                .build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(id)).thenReturn("val-2");
+
+        trans.apply(finder, template, 0);
+
+        verify(template).setImageViewResource(0, 2);
+    }
+
+    @Test
+    public void twoOptionsMatch() throws Exception {
+        AutofillId id = new AutofillId(1);
+        ImageTransformation trans = new ImageTransformation
+                .Builder(id, Pattern.compile(".*a.*"), 1)
+                .addOption(Pattern.compile(".*b.*"), 2)
+                .build();
+
+        ValueFinder finder = mock(ValueFinder.class);
+        RemoteViews template = mock(RemoteViews.class);
+
+        when(finder.findByAutofillId(id)).thenReturn("ab");
+
+        trans.apply(finder, template, 0);
+
+        // If two options match, the first one is picked
+        verify(template, only()).setImageViewResource(0, 1);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
index cfdb6e4..07c67eb9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
@@ -28,7 +28,6 @@
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
 
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -40,8 +39,8 @@
 public class InitializedCheckoutActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<InitializedCheckoutActivity> mActivityRule =
-        new ActivityTestRule<InitializedCheckoutActivity>(InitializedCheckoutActivity.class);
+    public final AutofillActivityTestRule<InitializedCheckoutActivity> mActivityRule =
+        new AutofillActivityTestRule<InitializedCheckoutActivity>(InitializedCheckoutActivity.class);
 
     private InitializedCheckoutActivity mCheckoutActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
index 81e3387..12fec5a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
@@ -38,8 +38,10 @@
 import android.service.autofill.FillContext;
 import android.service.autofill.FillResponse;
 import android.service.autofill.SaveCallback;
+import android.support.annotation.Nullable;
 import android.util.Log;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -51,6 +53,9 @@
  */
 public class InstrumentedAutoFillService extends AutofillService {
 
+    static final String SERVICE_NAME = InstrumentedAutoFillService.class.getPackage()
+            .getName() + "/." + InstrumentedAutoFillService.class.getSimpleName();
+
     private static final String TAG = "InstrumentedAutoFillService";
 
     private static final boolean DUMP_FILL_REQUESTS = false;
@@ -64,6 +69,9 @@
     private static final Replier sReplier = new Replier();
     private static final BlockingQueue<String> sConnectionStates = new LinkedBlockingQueue<>();
 
+    private static final Object sLock = new Object();
+
+    // @GuardedBy("sLock")
     private static boolean sIgnoreUnexpectedRequests = false;
 
     public InstrumentedAutoFillService() {
@@ -89,9 +97,11 @@
     @Override
     public void onFillRequest(android.service.autofill.FillRequest request,
             CancellationSignal cancellationSignal, FillCallback callback) {
-        if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts()))  {
-            Log.w(TAG, "Ignoring onFillRequest()");
-            return;
+        synchronized (sLock) {
+            if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts()))  {
+                Log.w(TAG, "Ignoring onFillRequest()");
+                return;
+            }
         }
         if (DUMP_FILL_REQUESTS) dumpStructure("onFillRequest()", request.getFillContexts());
         sReplier.onFillRequest(request.getFillContexts(), request.getClientState(),
@@ -101,9 +111,11 @@
     @Override
     public void onSaveRequest(android.service.autofill.SaveRequest request,
             SaveCallback callback) {
-        if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts())) {
-            Log.w(TAG, "Ignoring onSaveRequest()");
-            return;
+        synchronized (sLock) {
+            if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts())) {
+                Log.w(TAG, "Ignoring onSaveRequest()");
+                return;
+            }
         }
         if (DUMP_SAVE_REQUESTS) dumpStructure("onSaveRequest()", request.getFillContexts());
         sReplier.onSaveRequest(request.getFillContexts(), request.getClientState(), callback);
@@ -126,7 +138,9 @@
      * should throw an exception.
      */
     public static void setIgnoreUnexpectedRequests(boolean ignore) {
-        sIgnoreUnexpectedRequests = ignore;
+        synchronized (sLock) {
+            sIgnoreUnexpectedRequests = ignore;
+        }
     }
 
     /**
@@ -231,10 +245,28 @@
         private final BlockingQueue<FillRequest> mFillRequests = new LinkedBlockingQueue<>();
         private final BlockingQueue<SaveRequest> mSaveRequests = new LinkedBlockingQueue<>();
 
+        private List<Exception> mExceptions;
+
         private Replier() {
         }
 
         /**
+         * Gets the exceptions thrown asynchronously, if any.
+         */
+        @Nullable List<Exception> getExceptions() {
+            return mExceptions;
+        }
+
+        private void addException(@Nullable Exception e) {
+            if (e == null) return;
+
+            if (mExceptions == null) {
+                mExceptions = new ArrayList<>();
+            }
+            mExceptions.add(e);
+        }
+
+        /**
          * Sets the expectation for the next {@code onFillRequest} as {@link FillResponse} with just
          * one {@link Dataset}.
          */
@@ -280,6 +312,13 @@
         }
 
         /**
+         * Gets the current number of unhandled requests.
+         */
+        int getNumberUnhandledFillRequests() {
+            return mFillRequests.size();
+        }
+
+        /**
          * Gets the next save request, in the order received.
          *
          * <p>Typically called at the end of a test case, to assert the initial request.
@@ -310,6 +349,7 @@
             mResponses.clear();
             mFillRequests.clear();
             mSaveRequests.clear();
+            mExceptions = null;
         }
 
         private void onFillRequest(List<FillContext> contexts, Bundle data,
@@ -321,11 +361,14 @@
                 } catch (InterruptedException e) {
                     Log.w(TAG, "Interrupted getting CannedResponse: " + e);
                     Thread.currentThread().interrupt();
+                    addException(e);
                     return;
                 }
                 if (response == null) {
-                    dumpStructure("onFillRequest() without response", contexts);
-                    throw new RetryableException("No CannedResponse");
+                    final String msg = "onFillRequest() received when no CannedResponse was set";
+                    dumpStructure(msg, contexts);
+                    addException(new RetryableException(msg));
+                    return;
                 }
                 if (response.getResponseType() == NULL) {
                     Log.d(TAG, "onFillRequest(): replying with null");
@@ -350,6 +393,8 @@
 
                 Log.v(TAG, "onFillRequest(): fillResponse = " + fillResponse);
                 callback.onSuccess(fillResponse);
+            } catch (Exception e) {
+                addException(e);
             } finally {
                 mFillRequests.offer(new FillRequest(contexts, data, cancellationSignal, callback,
                         flags));
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
index 9a0d70c..1206c62 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
@@ -20,8 +20,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
-import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
@@ -50,6 +50,7 @@
 
     static final String ID_USERNAME_CONTAINER = "username_container";
     static final String AUTHENTICATION_MESSAGE = "Authentication failed. D'OH!";
+    static final String BACKDOOR_USERNAME = "LemmeIn";
 
     private TextView mUsernameLabel;
     private EditText mUsernameEditText;
@@ -110,7 +111,10 @@
     private void login() {
         final String username = mUsernameEditText.getText().toString();
         final String password = mPasswordEditText.getText().toString();
-        final boolean valid = username.equals(password) || password.contains("pass");
+        final boolean valid = username.equals(password)
+                || (TextUtils.isEmpty(username) && TextUtils.isEmpty(password))
+                || password.contains("pass")
+                || username.equals(BACKDOOR_USERNAME);
 
         if (valid) {
             Log.d(TAG, "login ok: " + username);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 686a056..82cc39f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -18,12 +18,13 @@
 
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.Activity.RESULT_OK;
+import static android.autofillservice.cts.CannedFillResponse.DO_NOT_REPLY_RESPONSE;
 import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
 import static android.autofillservice.cts.CheckoutActivity.ID_CC_NUMBER;
-import static android.autofillservice.cts.CannedFillResponse.DO_NOT_REPLY_RESPONSE;
 import static android.autofillservice.cts.Helper.ID_PASSWORD;
 import static android.autofillservice.cts.Helper.ID_PASSWORD_LABEL;
 import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.assertNoDanglingSessions;
 import static android.autofillservice.cts.Helper.assertNumberOfChildren;
 import static android.autofillservice.cts.Helper.assertTextAndValue;
 import static android.autofillservice.cts.Helper.assertTextIsSanitized;
@@ -31,12 +32,14 @@
 import static android.autofillservice.cts.Helper.dumpStructure;
 import static android.autofillservice.cts.Helper.eventually;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.runShellCommand;
 import static android.autofillservice.cts.Helper.setUserComplete;
 import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilConnected;
 import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilDisconnected;
 import static android.autofillservice.cts.LoginActivity.AUTHENTICATION_MESSAGE;
 import static android.autofillservice.cts.LoginActivity.ID_USERNAME_CONTAINER;
+import static android.autofillservice.cts.LoginActivity.BACKDOOR_USERNAME;
 import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
 import static android.service.autofill.FillEventHistory.Event.TYPE_AUTHENTICATION_SELECTED;
 import static android.service.autofill.FillEventHistory.Event.TYPE_DATASET_AUTHENTICATION_SELECTED;
@@ -70,9 +73,7 @@
 import android.graphics.Color;
 import android.os.Bundle;
 import android.service.autofill.FillEventHistory;
-import android.service.autofill.FillResponse;
 import android.service.autofill.SaveInfo;
-import android.support.test.rule.ActivityTestRule;
 import android.support.test.uiautomator.UiObject2;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
@@ -99,8 +100,8 @@
 public class LoginActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<LoginActivity> mActivityRule = new ActivityTestRule<LoginActivity>(
-            LoginActivity.class);
+    public final AutofillActivityTestRule<LoginActivity> mActivityRule =
+        new AutofillActivityTestRule<LoginActivity>(LoginActivity.class);
 
     private LoginActivity mActivity;
 
@@ -1172,7 +1173,7 @@
             throw e;
         }
 
-        // Sanity check: once saved, the session should be finsihed.
+        // Sanity check: once saved, the session should be finished.
         assertNoDanglingSessions();
     }
 
@@ -1187,7 +1188,6 @@
         saveGoesAway(DismissType.HOME_BUTTON);
     }
 
-    /* TODO: add these when fixed.
     @Test
     public void testSaveGoesAwayWhenTappingBackButton() throws Exception {
         saveGoesAway(DismissType.BACK_BUTTON);
@@ -1197,7 +1197,6 @@
     public void testSaveGoesAwayWhenTouchingOutside() throws Exception {
         saveGoesAway(DismissType.TOUCH_OUTSIDE);
     }
-    */
 
     private void saveGoesAway(DismissType dismissType) throws Exception {
         enableService();
@@ -1407,6 +1406,88 @@
     }
 
     @Test
+    public void testSaveNoRequiredField_NoneFilled() throws Exception {
+        optionalOnlyTest(FilledFields.NONE);
+    }
+
+    @Test
+    public void testSaveNoRequiredField_OneFilled() throws Exception {
+        optionalOnlyTest(FilledFields.USERNAME_ONLY);
+    }
+
+    @Test
+    public void testSaveNoRequiredField_BothFilled() throws Exception {
+        optionalOnlyTest(FilledFields.BOTH);
+    }
+
+    enum FilledFields {
+        NONE,
+        USERNAME_ONLY,
+        BOTH
+    }
+
+    private void optionalOnlyTest(FilledFields filledFields) throws Exception {
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD)
+                .setOptionalSavableIds(ID_USERNAME, ID_PASSWORD)
+                .build());
+
+        // Trigger auto-fill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Sanity check.
+        sUiBot.assertNoDatasets();
+
+        // Wait for onFill() before proceeding, otherwise the fields might be changed before
+        // the session started
+        sReplier.getNextFillRequest();
+
+        // Set credentials...
+        final String expectedUsername;
+        if (filledFields == FilledFields.USERNAME_ONLY || filledFields == FilledFields.BOTH) {
+            expectedUsername = BACKDOOR_USERNAME;
+            mActivity.onUsername((v) -> v.setText(BACKDOOR_USERNAME));
+        } else {
+            expectedUsername = "";
+        }
+        mActivity.onPassword(View::requestFocus);
+        if (filledFields == FilledFields.BOTH) {
+            mActivity.onPassword((v) -> v.setText("whatever"));
+        }
+
+        // ...and login
+        final String expectedMessage = getWelcomeMessage(expectedUsername);
+        final String actualMessage = mActivity.tapLogin();
+        assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
+
+        if (filledFields == FilledFields.NONE) {
+            sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
+            assertNoDanglingSessions();
+            return;
+        }
+
+        // Assert the snack bar is shown and tap "Save".
+        sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
+
+        final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+
+        // Assert value of expected fields - should not be sanitized.
+        final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME);
+        assertTextAndValue(username, BACKDOOR_USERNAME);
+
+        if (filledFields == FilledFields.BOTH) {
+            final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD);
+            assertTextAndValue(password, "whatever");
+        }
+
+        // Sanity check: once saved, the session should be finished.
+        assertNoDanglingSessions();
+    }
+
+    @Test
     public void testGenericSave() throws Exception {
         customizedSaveTest(SAVE_DATA_TYPE_GENERIC);
     }
@@ -2963,4 +3044,29 @@
             setUserComplete(getContext(), true);
         }
     }
+
+    @Test
+    public void testPopupGoesAwayWhenServiceIsChanged() throws Exception {
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedDataset.Builder()
+                .setField(ID_USERNAME, "dude")
+                .setField(ID_PASSWORD, "sweet")
+                .setPresentation(createPresentation("The Dude"))
+                .build());
+        mActivity.expectAutoFill("dude", "sweet");
+
+        // Trigger auto-fill.
+        mActivity.onUsername(View::requestFocus);
+        sReplier.getNextFillRequest();
+        sUiBot.assertDatasets("The Dude");
+
+        // Now disable service by setting another service
+        Helper.enableAutofillService(getContext(), NoOpAutofillService.SERVICE_NAME);
+
+        // ...and make sure popup's gone
+        sUiBot.assertNoDatasets();
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
new file mode 100644
index 0000000..09600a8
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.service.autofill.LuhnChecksumValidator;
+import android.service.autofill.ValueFinder;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.autofill.AutofillId;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class LuhnChecksumValidatorTest {
+
+    @Test
+    public void nullId() {
+        assertThrows(NullPointerException.class,
+                () -> new LuhnChecksumValidator((AutofillId[]) null));
+    }
+
+    @Test
+    public void nullAndOtherId() {
+        assertThrows(NullPointerException.class,
+                () -> new LuhnChecksumValidator(new AutofillId(1), null));
+    }
+
+    @Test
+    public void duplicateFields() {
+        AutofillId id = new AutofillId(1);
+
+        // duplicate fields are allowed
+        LuhnChecksumValidator validator = new LuhnChecksumValidator(id, id);
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        // 5 is a valid checksum for 0005000
+        when(finder.findByAutofillId(id)).thenReturn("0005");
+        assertThat(validator.isValid(finder)).isTrue();
+
+        // 6 is a not a valid checksum for 0006000
+        when(finder.findByAutofillId(id)).thenReturn("0006");
+        assertThat(validator.isValid(finder)).isFalse();
+    }
+
+    @Test
+    public void leadingZerosAreIgnored() {
+        AutofillId id = new AutofillId(1);
+
+        LuhnChecksumValidator validator = new LuhnChecksumValidator(id);
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        when(finder.findByAutofillId(id)).thenReturn("7992739871-3");
+        assertThat(validator.isValid(finder)).isTrue();
+
+        when(finder.findByAutofillId(id)).thenReturn("07992739871-3");
+        assertThat(validator.isValid(finder)).isTrue();
+    }
+
+    @Test
+    public void onlyOneChecksumValid() {
+        AutofillId id = new AutofillId(1);
+
+        LuhnChecksumValidator validator = new LuhnChecksumValidator(id);
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        for (int i = 0; i < 10; i++) {
+            when(finder.findByAutofillId(id)).thenReturn("7992739871-" + i);
+            assertThat(validator.isValid(finder)).isEqualTo(i == 3);
+        }
+    }
+
+    @Test
+    public void nullAutofillValuesCauseFailure() {
+        AutofillId id1 = new AutofillId(1);
+        AutofillId id2 = new AutofillId(2);
+        AutofillId id3 = new AutofillId(3);
+
+        LuhnChecksumValidator validator = new LuhnChecksumValidator(id1, id2, id3);
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        when(finder.findByAutofillId(id1)).thenReturn("7992739871");
+        when(finder.findByAutofillId(id2)).thenReturn(null);
+        when(finder.findByAutofillId(id3)).thenReturn("3");
+
+        assertThat(validator.isValid(finder)).isFalse();
+    }
+
+    @Test
+    public void nonDigits() {
+        AutofillId id = new AutofillId(1);
+
+        LuhnChecksumValidator validator = new LuhnChecksumValidator(id);
+
+        ValueFinder finder = mock(ValueFinder.class);
+        when(finder.findByAutofillId(id)).thenReturn("a7B9^9\n2 7{3\b9\08\uD83C\uDF2D7-1_3$");
+        assertThat(validator.isValid(finder)).isTrue();
+    }
+
+    @Test
+    public void multipleFieldNumber() {
+        AutofillId id1 = new AutofillId(1);
+        AutofillId id2 = new AutofillId(2);
+
+        LuhnChecksumValidator validator = new LuhnChecksumValidator(id1, id2);
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        when(finder.findByAutofillId(id1)).thenReturn("7992739871");
+        when(finder.findByAutofillId(id2)).thenReturn("3");
+        assertThat(validator.isValid(finder)).isTrue();
+
+        when(finder.findByAutofillId(id2)).thenReturn("2");
+        assertThat(validator.isValid(finder)).isFalse();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultipleExceptionsCatcher.java b/tests/autofillservice/src/android/autofillservice/cts/MultipleExceptionsCatcher.java
new file mode 100644
index 0000000..3750c30
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultipleExceptionsCatcher.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper used to catch multiple exceptions that might have happened in a test case.
+ */
+// TODO: move to common CTS code (and add test cases to it)
+public final class MultipleExceptionsCatcher {
+
+    private static final String TAG = "MultipleExceptionsCatcher";
+
+    private final List<Throwable> mThrowables = new ArrayList<>();
+
+    /**
+     * Runs {@code r} postponing any thrown exception to {@link #throwIfAny()}.
+     */
+    public MultipleExceptionsCatcher run(@NonNull Runnable r) {
+        try {
+            r.run();
+        } catch (Throwable t) {
+            mThrowables.add(t);
+        }
+        return this;
+    }
+
+    /**
+     * Adds an exception - if it's not {@code null} to the exceptions thrown by
+     * {@link #throwIfAny()}.
+     */
+    public MultipleExceptionsCatcher add(@Nullable Throwable t) {
+        if (t != null) {
+            mThrowables.add(t);
+        }
+        return this;
+    }
+
+    /**
+     * Throws one exception merging all exceptions thrown or added so far, if any.
+     */
+    public void throwIfAny() throws Exception {
+        if (mThrowables.isEmpty()) return;
+
+        if (mThrowables.size() == 1) {
+            final Throwable t = mThrowables.get(0);
+            if (t instanceof Exception) {
+                throw (Exception) t;
+            }
+        }
+
+        String msg = "D'OH!";
+        try {
+            try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
+                sw.write("Caught " + mThrowables.size() + " exceptions\n");
+                for (int i = 0; i < mThrowables.size(); i++) {
+                    sw.write("\n---- Begin of exception #" + (i + 1) + " ----\n");
+                    final Throwable exception = mThrowables.get(i);
+                    exception.printStackTrace(pw);
+                    sw.write("---- End of exception #" + (i + 1) + " ----\n\n");
+                }
+                msg = sw.toString();
+            }
+        } catch (IOException e) {
+            // ignore close() errors - should not happen...
+            Log.e(TAG, "Exception closing StringWriter: " + e);
+        }
+        throw new AssertionError(msg);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
index ac7ae34..3e30b9b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
@@ -28,7 +28,6 @@
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
 import android.os.Bundle;
-import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 import android.view.autofill.AutofillValue;
 import android.widget.EditText;
@@ -40,8 +39,8 @@
 public class MultipleFragmentLoginTest extends AutoFillServiceTestCase {
     private static final String LOG_TAG = MultipleFragmentLoginTest.class.getSimpleName();
     @Rule
-    public final ActivityTestRule<FragmentContainerActivity> mActivityRule =
-            new ActivityTestRule<>(FragmentContainerActivity.class);
+    public final AutofillActivityTestRule<FragmentContainerActivity> mActivityRule =
+            new AutofillActivityTestRule<>(FragmentContainerActivity.class);
     private FragmentContainerActivity mActivity;
     private EditText mEditText1;
     private EditText mEditText2;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/NoOpAutofillService.java b/tests/autofillservice/src/android/autofillservice/cts/NoOpAutofillService.java
new file mode 100644
index 0000000..4255b6d
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/NoOpAutofillService.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.autofillservice.cts;
+
+import android.os.CancellationSignal;
+import android.service.autofill.AutofillService;
+import android.service.autofill.FillCallback;
+import android.service.autofill.FillRequest;
+import android.service.autofill.SaveCallback;
+import android.service.autofill.SaveRequest;
+
+/**
+ * {@link AutofillService} implementation that does not do anything...
+ */
+public class NoOpAutofillService extends AutofillService {
+
+    static final String SERVICE_NAME = NoOpAutofillService.class.getPackage().getName()
+            + "/." + NoOpAutofillService.class.getSimpleName();
+
+    @Override
+    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
+            FillCallback callback) {
+    }
+
+    @Override
+    public void onSaveRequest(SaveRequest request, SaveCallback callback) {
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
index b1250de..05d5ecc 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
@@ -15,6 +15,7 @@
  */
 package android.autofillservice.cts;
 
+import static android.autofillservice.cts.Helper.assertNoDanglingSessions;
 import static android.autofillservice.cts.Helper.assertTextAndValue;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
 import static android.autofillservice.cts.OptionalSaveActivity.ID_ADDRESS1;
@@ -28,7 +29,6 @@
 import android.app.assist.AssistStructure;
 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.After;
 import org.junit.Before;
@@ -49,8 +49,8 @@
 public class OptionalSaveActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<OptionalSaveActivity> mActivityRule =
-        new ActivityTestRule<OptionalSaveActivity>(OptionalSaveActivity.class);
+    public final AutofillActivityTestRule<OptionalSaveActivity> mActivityRule =
+        new AutofillActivityTestRule<OptionalSaveActivity>(OptionalSaveActivity.class);
 
     private OptionalSaveActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index cd854c8..d458940 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -25,6 +25,7 @@
 import static android.autofillservice.cts.GridActivity.ID_L4C2;
 import static android.autofillservice.cts.Helper.assertTextIsSanitized;
 import static android.autofillservice.cts.Helper.assertValue;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.getMaxPartitions;
 import static android.autofillservice.cts.Helper.setMaxPartitions;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
@@ -45,7 +46,6 @@
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.service.autofill.FillResponse;
-import android.support.test.rule.ActivityTestRule;
 import android.widget.RemoteViews;
 
 import org.junit.Before;
@@ -58,8 +58,8 @@
 public class PartitionedActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<GridActivity> mActivityRule =
-        new ActivityTestRule<GridActivity>(GridActivity.class);
+    public final AutofillActivityTestRule<GridActivity> mActivityRule =
+        new AutofillActivityTestRule<GridActivity>(GridActivity.class);
 
     private GridActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
index 349149f..75c742f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
@@ -27,7 +27,6 @@
 
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.After;
 import org.junit.Before;
@@ -40,8 +39,8 @@
 public class PreFilledLoginActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<PreFilledLoginActivity> mActivityRule =
-            new ActivityTestRule<PreFilledLoginActivity>(PreFilledLoginActivity.class);
+    public final AutofillActivityTestRule<PreFilledLoginActivity> mActivityRule =
+            new AutofillActivityTestRule<PreFilledLoginActivity>(PreFilledLoginActivity.class);
 
     private PreFilledLoginActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java b/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
new file mode 100644
index 0000000..f93dd89
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import android.service.autofill.SaveInfo;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.autofill.AutofillId;
+
+import static org.testng.Assert.assertThrows;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SaveInfoTest {
+
+    @Test
+    public void testRequiredIdsBuilder_null() {
+        assertThrows(IllegalArgumentException.class,
+                () -> new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC, null));
+    }
+
+    @Test
+    public void testRequiredIdsBuilder_empty() {
+        assertThrows(IllegalArgumentException.class,
+                () -> new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC, new AutofillId[] {}));
+    }
+
+    @Test
+    public void testRequiredIdsBuilder_nullEntry() {
+        assertThrows(IllegalArgumentException.class,
+                () -> new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC,
+                        new AutofillId[] { null }));
+    }
+
+    @Test
+    public void testBuild_noOptionalIds() {
+        final SaveInfo.Builder builder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC);
+        assertThrows(IllegalStateException.class, ()-> builder.build());
+    }
+
+    @Test
+    public void testSetOptionalIds_null() {
+        final SaveInfo.Builder builder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC,
+                new AutofillId[] { new AutofillId(42) });
+        assertThrows(IllegalArgumentException.class, ()-> builder.setOptionalIds(null));
+    }
+
+    @Test
+    public void testSetOptional_empty() {
+        final SaveInfo.Builder builder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC,
+                new AutofillId[] { new AutofillId(42) });
+        assertThrows(IllegalArgumentException.class,
+                () -> builder.setOptionalIds(new AutofillId[] {}));
+    }
+
+    @Test
+    public void testSetOptional_nullEntry() {
+        final SaveInfo.Builder builder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC,
+                new AutofillId[] { new AutofillId(42) });
+        assertThrows(IllegalArgumentException.class,
+                () -> builder.setOptionalIds(new AutofillId[] { null }));
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index c5a0105..b0f5756 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -21,9 +21,11 @@
 import static android.autofillservice.cts.Helper.ID_USERNAME;
 import static android.autofillservice.cts.Helper.LANDSCAPE;
 import static android.autofillservice.cts.Helper.PORTRAIT;
+import static android.autofillservice.cts.Helper.assertNoDanglingSessions;
 import static android.autofillservice.cts.Helper.assertTextAndValue;
 import static android.autofillservice.cts.Helper.eventually;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.getOutOfProcessPid;
 import static android.autofillservice.cts.Helper.runShellCommand;
 import static android.autofillservice.cts.Helper.setOrientation;
@@ -56,8 +58,8 @@
     private static final String CANCEL_FULL_ID = "android.autofillservice.cts:id/cancel";
 
     @Before
-    public void removeAllSessions() {
-        destroyAllSessions();
+    public void cleanUpState() {
+        Helper.preTestCleanup();
     }
 
     /**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SimpleRegexValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/SimpleRegexValidatorTest.java
new file mode 100644
index 0000000..0b207b8
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/SimpleRegexValidatorTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.service.autofill.SimpleRegexValidator;
+import android.service.autofill.ValueFinder;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.autofill.AutofillId;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class SimpleRegexValidatorTest {
+
+    @Test
+    public void allNullConstructor() {
+        assertThrows(NullPointerException.class, () -> new SimpleRegexValidator(null, null));
+    }
+
+    @Test
+    public void nullRegexConstructor() {
+        assertThrows(NullPointerException.class,
+                () -> new SimpleRegexValidator(new AutofillId(1), null));
+    }
+
+    @Test
+    public void nullAutofillIdConstructor() {
+        assertThrows(NullPointerException.class,
+                () -> new SimpleRegexValidator(null, Pattern.compile(".")));
+    }
+
+    @Test
+    public void unknownField() {
+        AutofillId unknownId = new AutofillId(42);
+
+        SimpleRegexValidator validator = new SimpleRegexValidator(unknownId, Pattern.compile(".*"));
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        when(finder.findByAutofillId(unknownId)).thenReturn(null);
+        assertThat(validator.isValid(finder)).isFalse();
+    }
+
+    @Test
+    public void singleFieldValid() {
+        AutofillId creditCardFieldId = new AutofillId(1);
+        SimpleRegexValidator validator = new SimpleRegexValidator(creditCardFieldId,
+                Pattern.compile("^\\s*\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?(\\d{4})\\s*$"));
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        when(finder.findByAutofillId(creditCardFieldId)).thenReturn("1234 5678 9012 3456");
+        assertThat(validator.isValid(finder)).isTrue();
+
+        when(finder.findByAutofillId(creditCardFieldId)).thenReturn("invalid");
+        assertThat(validator.isValid(finder)).isFalse();
+    }
+
+    @Test
+    public void singleFieldInvalid() {
+        AutofillId id = new AutofillId(1);
+        SimpleRegexValidator validator = new SimpleRegexValidator(id, Pattern.compile("\\d*"));
+
+        ValueFinder finder = mock(ValueFinder.class);
+
+        when(finder.findByAutofillId(id)).thenReturn("123a456");
+
+        // Regex has to match the whole value
+        assertThat(validator.isValid(finder)).isFalse();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
index d8651b6..8135eba 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class TimePickerClockActivityTest extends TimePickerTestCase<TimePickerClockActivity> {
 
     @Rule
-    public final ActivityTestRule<TimePickerClockActivity> mActivityRule =
-        new ActivityTestRule<TimePickerClockActivity>(TimePickerClockActivity.class);
+    public final AutofillActivityTestRule<TimePickerClockActivity> mActivityRule =
+        new AutofillActivityTestRule<TimePickerClockActivity>(TimePickerClockActivity.class);
 
     @Override
     protected TimePickerClockActivity getTimePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
index ab86255..2d97f03 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class TimePickerSpinnerActivityTest extends TimePickerTestCase<TimePickerSpinnerActivity> {
 
     @Rule
-    public final ActivityTestRule<TimePickerSpinnerActivity> mActivityRule =
-        new ActivityTestRule<TimePickerSpinnerActivity>(TimePickerSpinnerActivity.class);
+    public final AutofillActivityTestRule<TimePickerSpinnerActivity> mActivityRule =
+        new AutofillActivityTestRule<TimePickerSpinnerActivity>(TimePickerSpinnerActivity.class);
 
     @Override
     protected TimePickerSpinnerActivity getTimePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
new file mode 100644
index 0000000..48728b2
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.assertNoDanglingSessions;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import android.service.autofill.LuhnChecksumValidator;
+import android.service.autofill.SimpleRegexValidator;
+import android.service.autofill.Validator;
+import android.service.autofill.Validators;
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.view.autofill.AutofillId;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.function.BiFunction;
+import java.util.regex.Pattern;
+
+public class ValidatorTest extends AutoFillServiceTestCase {
+    @Rule
+    public final AutofillActivityTestRule<LoginActivity> mActivityRule =
+        new AutofillActivityTestRule<>(LoginActivity.class);
+
+    private LoginActivity mActivity;
+
+    @Before
+    public void setActivity() {
+        mActivity = mActivityRule.getActivity();
+    }
+
+    @After
+    public void finishWelcomeActivity() {
+        WelcomeActivity.finishIt();
+    }
+
+    /**
+     * Base test
+     *
+     * @param validatorBuilder method to build a validator
+     * @param willSaveBeShown  Whether the save pop-up will be shown
+     */
+    private void testValidator(
+            @NonNull BiFunction<AutofillId, AutofillId, Validator> validatorBuilder,
+            boolean willSaveBeShown) throws Exception {
+        enableService();
+
+        AutofillId usernameId = mActivity.getUsername().getAutofillId();
+        AutofillId passwordId = mActivity.getPassword().getAutofillId();
+
+        // Set response
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_USERNAME, ID_PASSWORD)
+                .setValidator(validatorBuilder.apply(usernameId, passwordId))
+                .build());
+
+        // Trigger auto-fill
+        mActivity.onPassword(View::requestFocus);
+
+        // Wait for onFill() before proceeding.
+        sReplier.getNextFillRequest();
+
+        // Trigger save.
+        mActivity.onUsername((v) -> v.setText("7992739871-3"));
+        mActivity.onPassword((v) -> v.setText("passwd"));
+        mActivity.tapLogin();
+
+        if (willSaveBeShown) {
+            sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+            sReplier.getNextSaveRequest();
+        } else {
+            sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC);
+        }
+
+        assertNoDanglingSessions();
+    }
+
+    @Test
+    public void checkForInvalidField() throws Exception {
+        testValidator((usernameId, passwordId) -> Validators.or(
+                new LuhnChecksumValidator(new AutofillId(-1)),
+                new SimpleRegexValidator(passwordId, Pattern.compile("pass.*"))), true);
+    }
+
+    @Test
+    public void checkBoth() throws Exception {
+        testValidator((usernameId, passwordId) -> Validators.and(
+                new LuhnChecksumValidator(usernameId),
+                new SimpleRegexValidator(passwordId, Pattern.compile("pass.*"))), true);
+    }
+
+    @Test
+    public void checkEither1() throws Exception {
+        testValidator((usernameId, passwordId) -> Validators.or(
+                new SimpleRegexValidator(usernameId, Pattern.compile("7.*")),
+                new SimpleRegexValidator(passwordId, Pattern.compile("pass.*"))), true);
+    }
+
+    @Test
+    public void checkEither2() throws Exception {
+        testValidator((usernameId, passwordId) -> Validators.or(
+                new SimpleRegexValidator(usernameId, Pattern.compile("invalid")),
+                new SimpleRegexValidator(passwordId, Pattern.compile("pass.*"))), true);
+    }
+
+    @Test
+    public void checkBothButFail() throws Exception {
+        testValidator((usernameId, passwordId) -> Validators.and(
+                new SimpleRegexValidator(usernameId, Pattern.compile("7.*")),
+                new SimpleRegexValidator(passwordId, Pattern.compile("invalid"))), false);
+    }
+
+    @Test
+    public void checkEitherButFail() throws Exception {
+        testValidator((usernameId, passwordId) -> Validators.or(
+                new SimpleRegexValidator(usernameId, Pattern.compile("invalid")),
+                new SimpleRegexValidator(passwordId, Pattern.compile("invalid"))), false);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
index f33d6fe..541250b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
@@ -24,7 +24,6 @@
 import android.support.annotation.IdRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.autofill.AutofillValue;
@@ -40,8 +39,8 @@
 @RunWith(AndroidJUnit4.class)
 public class ViewAttributesTest extends AutoFillServiceTestCase {
     @Rule
-    public final ActivityTestRule<ViewAttributesTestActivity> mActivityRule =
-            new ActivityTestRule<>(ViewAttributesTestActivity.class);
+    public final AutofillActivityTestRule<ViewAttributesTestActivity> mActivityRule =
+            new AutofillActivityTestRule<>(ViewAttributesTestActivity.class);
 
     private ViewAttributesTestActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java
index 82bf213..7ec1114 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java
@@ -53,7 +53,7 @@
 
         setContentView(R.layout.virtual_container_activity);
 
-        mCustomView = (VirtualContainerView) findViewById(R.id.virtual_container_view);
+        mCustomView = findViewById(R.id.virtual_container_view);
 
         mUsername = mCustomView.addLine(ID_USERNAME_LABEL, "Username", ID_USERNAME, BLANK_VALUE);
         mPassword = mCustomView.addLine(ID_PASSWORD_LABEL, "Password", ID_PASSWORD, BLANK_VALUE);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
index f5e6832..8adbdd7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
@@ -36,7 +36,8 @@
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.VirtualContainerView.Line;
 import android.graphics.Rect;
-import android.support.test.rule.ActivityTestRule;
+import android.os.SystemClock;
+import android.service.autofill.SaveInfo;
 import android.support.test.uiautomator.UiObject2;
 import android.view.autofill.AutofillManager;
 
@@ -45,14 +46,17 @@
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Test case for an activity containing virtual children.
  */
 public class VirtualContainerActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<VirtualContainerActivity> mActivityRule =
-            new ActivityTestRule<VirtualContainerActivity>(VirtualContainerActivity.class);
+    public final AutofillActivityTestRule<VirtualContainerActivity> mActivityRule =
+            new AutofillActivityTestRule<VirtualContainerActivity>(VirtualContainerActivity.class);
 
     private VirtualContainerActivity mActivity;
 
@@ -369,6 +373,43 @@
         sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
     }
 
+    @Test
+    public void testSaveDialogShownWhenAllVirtualViewsNotVisible() throws Exception {
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+                .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE)
+                .build());
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        // Trigger auto-fill.
+        mActivity.runOnUiThread(() -> {
+            mActivity.mUsername.changeFocus(true);
+            latch.countDown();
+        });
+        latch.await(Helper.UI_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        sReplier.getNextFillRequest();
+
+        // TODO: 63602573 Should be removed once this bug is fixed
+        SystemClock.sleep(1000);
+
+        mActivity.runOnUiThread(() -> {
+            // Fill in some stuff
+            mActivity.mUsername.setText("foo");
+            mActivity.mPassword.setText("bar");
+
+            // Hide all virtual views
+            mActivity.mUsername.changeVisibility(false);
+            mActivity.mPassword.changeVisibility(false);
+        });
+
+        // Make sure save is shown
+        sUiBot.assertSaveShowing(SAVE_DATA_TYPE_PASSWORD);
+    }
 
     /**
      * Asserts the dataset picker is properly displayed in a give line.
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
index aa5d67b..e10c4ff 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
@@ -125,6 +125,9 @@
         for (int i = 0; i < mLines.size(); i++) {
             x = mLeftMargin;
             final Line line = mLines.get(i);
+            if (!line.visible) {
+                continue;
+            }
             Log.v(TAG, "Drawing '" + line + "' at " + x + "x" + y);
             mTextPaint.setColor(line.focused ? mFocusedColor : mUnfocusedColor);
             final String readOnlyText = line.label.text + ":  [";
@@ -260,6 +263,7 @@
         final Rect bounds = new Rect();
 
         private boolean focused;
+        private boolean visible = true;
 
         private Line(String labelId, String label, String textId, String text) {
             this.label = new Item(this, ++nextId, labelId, label, false, false);
@@ -278,6 +282,16 @@
             }
         }
 
+        void changeVisibility(boolean visible) {
+            if (this.visible == visible) {
+                return;
+            }
+            this.visible = visible;
+            mAfm.notifyViewVisibilityChanged(VirtualContainerView.this, text.id, visible);
+            Log.d(TAG, "visibility changed view: " + text.id + "; visible:" + visible);
+            invalidate();
+        }
+
         Rect getAbsCoordinates() {
             // Must offset the boundaries so they're relative to the CustomView.
             final int offset[] = new int[2];
@@ -290,13 +304,25 @@
             return absBounds;
         }
 
+        void setText(String value) {
+            text.text = value;
+            final AutofillManager autofillManager =
+                    getContext().getSystemService(AutofillManager.class);
+            if (autofillManager != null) {
+                autofillManager.notifyValueChanged(VirtualContainerView.this, text.id,
+                        AutofillValue.forText(text.text));
+            }
+            invalidate();
+        }
+
         void setTextChangedListener(TextWatcher listener) {
             text.listener = listener;
         }
 
         @Override
         public String toString() {
-            return "Label: " + label + " Text: " + text + " Focused: " + focused;
+            return "Label: " + label + " Text: " + text + " Focused: " + focused
+                    + " Visible: " + visible;
         }
 
         final class OneTimeLineWatcher implements TextWatcher {
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index c8c7d87..bb1f8fc 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsBackupTestCases
 
diff --git a/tests/backup/AndroidTest.xml b/tests/backup/AndroidTest.xml
index f292943..015f595 100644
--- a/tests/backup/AndroidTest.xml
+++ b/tests/backup/AndroidTest.xml
@@ -18,9 +18,14 @@
     <option name="config-descriptor:metadata" key="component" value="backup" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsBackupApp.apk" />
+        <option name="test-file-name" value="CtsFullBackupApp.apk" />
+        <option name="test-file-name" value="CtsKeyValueBackupApp.apk" />
         <option name="test-file-name" value="CtsBackupTestCases.apk" />
     </target_preparer>
+    <target_preparer class="android.cts.backup.BackupPreparer">
+        <option name="enable-backup-if-needed" value="true" />
+        <option name="select-local-transport" value="true" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.backup.cts" />
         <option name="runtime-hint" value="8m20s" />
diff --git a/tests/backup/app/Android.mk b/tests/backup/app/Android.mk
index dd1992b..cddf11e 100644
--- a/tests/backup/app/Android.mk
+++ b/tests/backup/app/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -14,21 +14,4 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsBackupApp
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    compatibility-device-util \
-    ctstestrunner
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/tests/backup/app/fullbackup/Android.mk
similarity index 65%
copy from hostsidetests/devicepolicy/app/VpnApp/Android.mk
copy to tests/backup/app/fullbackup/Android.mk
index 9723b97..ac53252 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/tests/backup/app/fullbackup/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -16,19 +16,19 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsVpnFirewallApp
-
 LOCAL_MODULE_TAGS := optional
 
 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)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_PACKAGE_NAME := CtsFullBackupApp
 
-LOCAL_SDK_VERSION := current
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    ctstestrunner
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/backup/app/AndroidManifest.xml b/tests/backup/app/fullbackup/AndroidManifest.xml
similarity index 95%
rename from tests/backup/app/AndroidManifest.xml
rename to tests/backup/app/fullbackup/AndroidManifest.xml
index 1507bc2..849b13f 100644
--- a/tests/backup/app/AndroidManifest.xml
+++ b/tests/backup/app/fullbackup/AndroidManifest.xml
@@ -20,7 +20,7 @@
 
     <application
         android:allowBackup="true"
-        android:backupAgent="BackupCtsBackupAgent"
+        android:backupAgent="FullBackupBackupAgent"
         android:label="Android Backup CTS App"
         android:fullBackupOnly="true">
         <activity
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/tests/backup/app/keyvalue/Android.mk
similarity index 65%
copy from hostsidetests/devicepolicy/app/VpnApp/Android.mk
copy to tests/backup/app/keyvalue/Android.mk
index 9723b97..3c36f50 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/tests/backup/app/keyvalue/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -16,19 +16,19 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsVpnFirewallApp
-
 LOCAL_MODULE_TAGS := optional
 
 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)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_PACKAGE_NAME := CtsKeyValueBackupApp
 
-LOCAL_SDK_VERSION := current
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    ctstestrunner
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/backup/app/AndroidManifest.xml b/tests/backup/app/keyvalue/AndroidManifest.xml
similarity index 78%
copy from tests/backup/app/AndroidManifest.xml
copy to tests/backup/app/keyvalue/AndroidManifest.xml
index 1507bc2..c99b4b4 100644
--- a/tests/backup/app/AndroidManifest.xml
+++ b/tests/backup/app/keyvalue/AndroidManifest.xml
@@ -16,16 +16,15 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.backup.app" >
+    package="android.backup.kvapp" >
 
     <application
         android:allowBackup="true"
-        android:backupAgent="BackupCtsBackupAgent"
-        android:label="Android Backup CTS App"
-        android:fullBackupOnly="true">
+        android:backupAgent="android.backup.app.KeyValueBackupAgent"
+        android:label="Android Key Value Backup CTS App">
         <activity
-            android:name=".MainActivity"
-            android:label="Android Backup CTS App" >
+            android:name="android.backup.app.MainActivity"
+            android:label="Android Key Value Backup CTS App" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java b/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
similarity index 62%
rename from tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java
rename to tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
index f6fb8c1..8535344 100644
--- a/tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java
+++ b/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
@@ -23,30 +23,43 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import java.io.File;
 import java.io.IOException;
 
 /*
- * Backup agent for Backup CTS App.
+ * Full Backup agent for Backup CTS App.
  *
  * Logs callbacks into logcat.
  */
-public class BackupCtsBackupAgent extends BackupAgent {
+public class FullBackupBackupAgent extends BackupAgent {
+
+    @Override
+    public void onCreate() {
+        Log.d(MainActivity.TAG, "onCreate");
+    }
 
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
                          ParcelFileDescriptor newState) throws IOException {
-        Log.d(MainActivity.TAG, "Backup requested");
+        throw new IllegalStateException("unexpected onBackup");
     }
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode,
                           ParcelFileDescriptor newState) throws IOException {
-        Log.d(MainActivity.TAG, "Restore requested");
+        throw new IllegalStateException("unexpected onRestore");
+    }
+
+    @Override
+    public void onRestoreFile(ParcelFileDescriptor data, long size,
+            File destination, int type, long mode, long mtime) throws IOException {
+        Log.d(MainActivity.TAG, "onRestoreFile " + destination);
+        super.onRestoreFile(data, size, destination, type, mode, mtime);
     }
 
     @Override
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
-        Log.d(MainActivity.TAG, "Full backup requested");
+        Log.d(MainActivity.TAG, "Full backup requested, quota is " + data.getQuota());
         super.onFullBackup(data);
     }
 
@@ -54,4 +67,15 @@
     public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
         Log.d(MainActivity.TAG, "Quota exceeded!");
     }
+
+    @Override
+    public void onRestoreFinished() {
+        Log.d(MainActivity.TAG, "onRestoreFinished");
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(MainActivity.TAG, "onDestroy");
+    }
+
 }
diff --git a/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java b/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
new file mode 100644
index 0000000..155d8f9
--- /dev/null
+++ b/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
@@ -0,0 +1,93 @@
+/*
+ * 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 android.backup.app;
+
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackupDataOutput;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/*
+ * Key Value Backup agent for Backup CTS App.
+ *
+ * Logs callbacks into logcat.
+ */
+public class KeyValueBackupAgent extends BackupAgent {
+
+    @Override
+    public void onCreate() {
+        Log.d(MainActivity.TAG, "onCreate");
+    }
+
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+                         ParcelFileDescriptor newState) throws IOException {
+        Log.d(MainActivity.TAG, "Backup requested, quota is " + data.getQuota());
+
+        // Always backup the entire file
+        File testFile = new File(getFilesDir(), MainActivity.FILE_NAME);
+        Log.d(MainActivity.TAG, "Writing " + testFile.length());
+
+        data.writeEntityHeader(MainActivity.FILE_NAME, (int) testFile.length());
+        byte[] buffer = new byte[4096];
+        try (FileInputStream input = new FileInputStream(testFile)) {
+            int read;
+            while ((read = input.read(buffer)) >= 0) {
+                data.writeEntityData(buffer, read);
+            }
+        }
+    }
+
+    @Override
+    public void onRestore(BackupDataInput data, int appVersionCode,
+                          ParcelFileDescriptor newState) throws IOException {
+        Log.d(MainActivity.TAG, "Restore requested");
+    }
+
+    @Override
+    public void onRestoreFile(ParcelFileDescriptor data, long size,
+            File destination, int type, long mode, long mtime) throws IOException {
+        throw new IllegalStateException("unexpected onRestoreFile");
+    }
+
+    @Override
+    public void onFullBackup(FullBackupDataOutput data) throws IOException {
+        throw new IllegalStateException("unexpected onFullBackup");
+    }
+
+    @Override
+    public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
+        Log.d(MainActivity.TAG, "Quota exceeded!");
+    }
+
+    @Override
+    public void onRestoreFinished() {
+        Log.d(MainActivity.TAG, "onRestoreFinished");
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(MainActivity.TAG, "onDestroy");
+    }
+
+}
diff --git a/tests/backup/app/src/android/backup/app/MainActivity.java b/tests/backup/app/src/android/backup/app/MainActivity.java
index 93c6dd6..3127a56 100644
--- a/tests/backup/app/src/android/backup/app/MainActivity.java
+++ b/tests/backup/app/src/android/backup/app/MainActivity.java
@@ -40,8 +40,8 @@
  */
 public class MainActivity extends Activity {
     public static final String TAG = "BackupCTSApp";
+    public static final String FILE_NAME = "file_name";
 
-    private static final String FILE_NAME = "file_name";
     private static final String FILE_SIZE_EXTRA = "file_size";
     private static final int DATA_CHUNK_SIZE = 1024 * 1024;
 
@@ -60,6 +60,7 @@
         } else {
             Log.d(TAG, "No file size was provided");
         }
+        finish();
     }
 
     private void createFile(int size) throws IOException {
diff --git a/tests/backup/src/android/backup/cts/BackupQuotaTest.java b/tests/backup/src/android/backup/cts/BackupQuotaTest.java
deleted file mode 100644
index 0493993..0000000
--- a/tests/backup/src/android/backup/cts/BackupQuotaTest.java
+++ /dev/null
@@ -1,183 +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 android.backup.cts;
-
-import android.app.Instrumentation;
-import android.content.pm.PackageManager;
-import android.os.ParcelFileDescriptor;
-import android.test.InstrumentationTestCase;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Verifies receiving quotaExceeded() callback on full backup.
- *
- * Uses test app that creates large file and receives the callback.
- * {@link com.android.internal.backup.LocalTransport} is used, it has size quota 25MB.
- */
-public class BackupQuotaTest extends InstrumentationTestCase {
-    private static final String APP_LOG_TAG = "BackupCTSApp";
-
-    private static final String LOCAL_TRANSPORT =
-            "android/com.android.internal.backup.LocalTransport";
-    private static final int LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE = 30 * 1024 * 1024;
-    private static final String BACKUP_APP_NAME = "android.backup.app";
-
-    private static final int SMALL_LOGCAT_DELAY = 1000;
-
-    private boolean isBackupSupported;
-    private boolean wasBackupEnabled;
-    private String oldTransport;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        PackageManager packageManager = getInstrumentation().getContext().getPackageManager();
-        isBackupSupported = packageManager != null
-                && packageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP);
-        if (!isBackupSupported) {
-            return;
-        }
-        // Enable backup and select local backup transport
-        assertTrue("LocalTransport should be available.", hasBackupTransport(LOCAL_TRANSPORT));
-        wasBackupEnabled = enableBackup(true);
-        oldTransport = setBackupTransport(LOCAL_TRANSPORT);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // Return old transport
-        if (isBackupSupported) {
-            setBackupTransport(oldTransport);
-            enableBackup(wasBackupEnabled);
-        }
-        super.tearDown();
-    }
-
-    public void testQuotaExceeded() throws Exception {
-        if (!isBackupSupported) {
-            return;
-        }
-        exec("logcat --clear");
-        exec("setprop log.tag." + APP_LOG_TAG +" VERBOSE");
-        // Launch test app and create file exceeding limit for local transport
-        exec("am start -W -a android.intent.action.MAIN " +
-                "-c android.intent.category.LAUNCHER " +
-                "-n " + BACKUP_APP_NAME + "/" + BACKUP_APP_NAME +".MainActivity " +
-                "-e file_size " + LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE);
-        assertTrue("File was not created", waitForLogcat("File created!", 30));
-
-        // Request backup and wait for quota exceeded event in logcat
-        exec("bmgr backupnow " + BACKUP_APP_NAME);
-        assertTrue("Quota exceeded event is not received", waitForLogcat("Quota exceeded!", 10));
-    }
-
-    private boolean enableBackup(boolean enable) throws Exception {
-        boolean previouslyEnabled;
-        String output = exec("bmgr enabled");
-        Pattern pattern = Pattern.compile("^Backup Manager currently (enabled|disabled)$");
-        Matcher matcher = pattern.matcher(output.trim());
-        if (matcher.find()) {
-            previouslyEnabled = "enabled".equals(matcher.group(1));
-        } else {
-            throw new RuntimeException("non-parsable output setting bmgr enabled: " + output);
-        }
-
-        exec("bmgr enable " + enable);
-        return previouslyEnabled;
-    }
-
-    private String setBackupTransport(String transport) throws Exception {
-        String output = exec("bmgr transport " + transport);
-        Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
-        Matcher matcher = pattern.matcher(output);
-        if (matcher.find()) {
-            return matcher.group(1);
-        } else {
-            throw new RuntimeException("non-parsable output setting bmgr transport: " + output);
-        }
-    }
-
-    private boolean hasBackupTransport(String transport) throws Exception {
-        String output = exec("bmgr list transports");
-        for (String t : output.split(" ")) {
-            if (transport.equals(t)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean waitForLogcat(String logcatString, int maxTimeoutInSeconds) throws Exception {
-        long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(maxTimeoutInSeconds);
-        while (timeout >= System.currentTimeMillis()) {
-            FileInputStream fis = executeStreamedShellCommand(getInstrumentation(),
-                    "logcat -v brief -d " + APP_LOG_TAG + ":* *:S");
-            BufferedReader log = new BufferedReader(new InputStreamReader(fis));
-            String line;
-            while ((line = log.readLine()) != null) {
-                if (line.contains(logcatString)) {
-                    return true;
-                }
-            }
-            closeQuietly(log);
-            // In case the key has not been found, wait for the log to update before
-            // performing the next search.
-            Thread.sleep(SMALL_LOGCAT_DELAY);
-        }
-        return false;
-    }
-
-    private String exec(String command) throws Exception {
-        BufferedReader br = null;
-        try (InputStream in = executeStreamedShellCommand(getInstrumentation(), command)) {
-            br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
-            String str = null;
-            StringBuilder out = new StringBuilder();
-            while ((str = br.readLine()) != null) {
-                out.append(str);
-            }
-            return out.toString();
-        }
-    }
-
-    private static FileInputStream executeStreamedShellCommand(Instrumentation instrumentation,
-                                                               String command) throws Exception {
-        final ParcelFileDescriptor pfd =
-                instrumentation.getUiAutomation().executeShellCommand(command);
-        return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-    }
-
-    private static void closeQuietly(AutoCloseable closeable) {
-        if (closeable != null) {
-            try {
-                closeable.close();
-            } catch (RuntimeException rethrown) {
-                throw rethrown;
-            } catch (Exception ignored) {
-            }
-        }
-    }
-}
diff --git a/tests/backup/src/android/backup/cts/BaseBackupCtsTest.java b/tests/backup/src/android/backup/cts/BaseBackupCtsTest.java
new file mode 100644
index 0000000..bbd0d26
--- /dev/null
+++ b/tests/backup/src/android/backup/cts/BaseBackupCtsTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.backup.cts;
+
+import android.app.Instrumentation;
+import android.content.pm.PackageManager;
+import android.os.ParcelFileDescriptor;
+import android.test.InstrumentationTestCase;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for backup instrumentation tests.
+ *
+ * Ensures that backup is enabled and local transport selected, and provides some utility methods.
+ */
+public class BaseBackupCtsTest extends InstrumentationTestCase {
+    private static final String APP_LOG_TAG = "BackupCTSApp";
+
+    private static final String LOCAL_TRANSPORT =
+            "android/com.android.internal.backup.LocalTransport";
+
+    private static final int SMALL_LOGCAT_DELAY = 1000;
+
+    private boolean isBackupSupported;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        PackageManager packageManager = getInstrumentation().getContext().getPackageManager();
+        isBackupSupported = packageManager != null
+                && packageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP);
+
+        if (isBackupSupported) {
+            assertTrue("Backup not enabled", isBackupEnabled());
+            assertTrue("LocalTransport not selected", isLocalTransportSelected());
+            exec("setprop log.tag." + APP_LOG_TAG +" VERBOSE");
+        }
+    }
+
+    public boolean isBackupSupported() {
+        return isBackupSupported;
+    }
+
+    private boolean isBackupEnabled() throws Exception {
+        String output = exec("bmgr enabled");
+        return output.contains("currently enabled");
+    }
+
+    private boolean isLocalTransportSelected() throws Exception {
+        String output = exec("bmgr list transports");
+        return output.contains("* " + LOCAL_TRANSPORT);
+    }
+
+    /**
+     * Attempts to clear logcat.
+     *
+     * Clearing logcat is known to be unreliable, so this methods also output a unique separator
+     * that can be used to find this point in the log even if clearing failed.
+     * @return a unique separator string
+     * @throws Exception
+     */
+    protected String clearLogcat() throws Exception {
+        exec("logcat -c");
+        String uniqueString = ":::" + UUID.randomUUID().toString();
+        exec("log -t " + APP_LOG_TAG + " " + uniqueString);
+        return uniqueString;
+    }
+
+    /**
+     * Wait for up to maxTimeoutInSeconds for the given strings to appear in the logcat in the given order.
+     * By passing the separator returned by {@link #clearLogcat} as the first string you can ensure that only
+     * logs emitted after that call to clearLogcat are found.
+     *
+     * @throws AssertionError if the strings are not found in the given time.
+     */
+    protected void waitForLogcat(int maxTimeoutInSeconds, String... logcatStrings)
+        throws Exception {
+        long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(maxTimeoutInSeconds);
+        int stringIndex = 0;
+        while (timeout >= System.currentTimeMillis()) {
+            FileInputStream fis = executeStreamedShellCommand(getInstrumentation(),
+                    "logcat -v brief -d " + APP_LOG_TAG + ":* *:S");
+            BufferedReader log = new BufferedReader(new InputStreamReader(fis));
+            String line;
+            stringIndex = 0;
+            while ((line = log.readLine()) != null) {
+                if (line.contains(logcatStrings[stringIndex])) {
+                    stringIndex++;
+                    if (stringIndex >= logcatStrings.length) {
+                        drainAndClose(log);
+                        return;
+                    }
+                }
+            }
+            closeQuietly(log);
+            // In case the key has not been found, wait for the log to update before
+            // performing the next search.
+            Thread.sleep(SMALL_LOGCAT_DELAY);
+        }
+        fail("Couldn't find " + logcatStrings[stringIndex] +
+            (stringIndex > 0 ? " after " + logcatStrings[stringIndex - 1] : "") +
+            " within " + maxTimeoutInSeconds + " seconds ");
+    }
+
+    protected void createTestFileOfSize(String packageName, int size) throws Exception {
+        exec("am start -a android.intent.action.MAIN " +
+            "-c android.intent.category.LAUNCHER " +
+            "-n " + packageName + "/android.backup.app.MainActivity " +
+            "-e file_size " + size);
+        waitForLogcat(30, "File created!");
+    }
+
+    protected String exec(String command) throws Exception {
+        try (InputStream in = executeStreamedShellCommand(getInstrumentation(), command)) {
+            BufferedReader br = new BufferedReader(
+                    new InputStreamReader(in, StandardCharsets.UTF_8));
+            String str;
+            StringBuilder out = new StringBuilder();
+            while ((str = br.readLine()) != null) {
+                out.append(str);
+            }
+            return out.toString();
+        }
+    }
+
+    private static FileInputStream executeStreamedShellCommand(Instrumentation instrumentation,
+                                                               String command) throws Exception {
+        final ParcelFileDescriptor pfd =
+                instrumentation.getUiAutomation().executeShellCommand(command);
+        return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+    }
+
+    private static void drainAndClose(BufferedReader reader) {
+        try {
+            while (reader.read() >= 0) {
+                // do nothing.
+            }
+        } catch (IOException ignored) {
+        }
+        closeQuietly(reader);
+    }
+
+    private static void closeQuietly(AutoCloseable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
+            }
+        }
+    }
+}
diff --git a/tests/backup/src/android/backup/cts/FullBackupLifecycleTest.java b/tests/backup/src/android/backup/cts/FullBackupLifecycleTest.java
new file mode 100644
index 0000000..beefa01
--- /dev/null
+++ b/tests/backup/src/android/backup/cts/FullBackupLifecycleTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.backup.cts;
+
+/**
+ * Verifies that key methods are called in expected order during backup / restore.
+ */
+public class FullBackupLifecycleTest extends BaseBackupCtsTest {
+
+    private static final String BACKUP_APP_NAME = "android.backup.app";
+
+    private static final int LOCAL_TRANSPORT_CONFORMING_FILE_SIZE = 5 * 1024;
+
+    private static final int TIMEOUT_SECONDS = 30;
+
+    public void testExpectedMethodsCalledInOrder() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        String backupSeparator = clearLogcat();
+
+        // Make sure there's something to backup
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_CONFORMING_FILE_SIZE);
+
+        // Request backup and wait for it to complete
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+
+        waitForLogcat(TIMEOUT_SECONDS,
+            backupSeparator,
+            "onCreate",
+            "Full backup requested",
+            "onDestroy");
+
+        String restoreSeparator = clearLogcat();
+
+        // Now request restore and wait for it to complete
+        exec("bmgr restore " + BACKUP_APP_NAME);
+
+        waitForLogcat(TIMEOUT_SECONDS,
+            restoreSeparator,
+            "onCreate",
+            "onRestoreFile",
+            "onRestoreFinished",
+            "onDestroy");
+    }
+
+}
diff --git a/tests/backup/src/android/backup/cts/FullBackupQuotaTest.java b/tests/backup/src/android/backup/cts/FullBackupQuotaTest.java
new file mode 100644
index 0000000..2343eb8
--- /dev/null
+++ b/tests/backup/src/android/backup/cts/FullBackupQuotaTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.backup.cts;
+
+/**
+ * Verifies receiving quotaExceeded() callback on full backup.
+ *
+ * Uses test app that creates large file and receives the callback.
+ * {@link com.android.internal.backup.LocalTransport} is used, it has size quota 25MB.
+ */
+public class FullBackupQuotaTest extends BaseBackupCtsTest {
+
+    private static final String BACKUP_APP_NAME = "android.backup.app";
+
+    // Should be the same as LocalTransport.FULL_BACKUP_SIZE_QUOTA
+    private static final int LOCAL_TRANSPORT_BACKUP_QUOTA = 25 * 1024 * 1024;
+    private static final int LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE = 30 * 1024 * 1024;
+
+    private static final int TIMEOUT_SECONDS = 30;
+
+    public void testQuotaExceeded() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        String separator = clearLogcat();
+        // Launch test app and create file exceeding limit for local transport
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE);
+
+        // Request backup and wait for quota exceeded event in logcat
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+        waitForLogcat(TIMEOUT_SECONDS,separator,
+            "Quota exceeded!");
+    }
+
+    public void testQuotaReported() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        String separator = clearLogcat();
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+        waitForLogcat(TIMEOUT_SECONDS,separator,
+            "quota is " + LOCAL_TRANSPORT_BACKUP_QUOTA);
+    }
+
+}
diff --git a/tests/backup/src/android/backup/cts/KeyValueLifecycleTest.java b/tests/backup/src/android/backup/cts/KeyValueLifecycleTest.java
new file mode 100644
index 0000000..d957bbc
--- /dev/null
+++ b/tests/backup/src/android/backup/cts/KeyValueLifecycleTest.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 android.backup.cts;
+
+/**
+ * Verifies that key methods are called in expected order during backup / restore.
+ */
+public class KeyValueLifecycleTest extends BaseBackupCtsTest {
+
+    private static final String BACKUP_APP_NAME = "android.backup.kvapp";
+
+    private static final int LOCAL_TRANSPORT_CONFORMING_FILE_SIZE = 5 * 1024;
+
+    private static final int TIMEOUT_SECONDS = 30;
+
+    public void testExpectedMethodsCalledInOrder() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        String backupSeparator = clearLogcat();
+
+        // Make sure there's something to backup
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_CONFORMING_FILE_SIZE);
+
+        // Request backup and wait for it to complete
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+
+        waitForLogcat(TIMEOUT_SECONDS,backupSeparator,
+            "onCreate",
+            "Backup requested",
+            "onDestroy");
+
+        String restoreSeparator = clearLogcat();
+
+        // Now request restore and wait for it to complete
+        exec("bmgr restore " + BACKUP_APP_NAME);
+
+        waitForLogcat(TIMEOUT_SECONDS, restoreSeparator,
+            "onCreate",
+            "Restore requested",
+            "onRestoreFinished",
+            "onDestroy");
+    }
+
+}
diff --git a/tests/backup/src/android/backup/cts/KeyValueQuotaTest.java b/tests/backup/src/android/backup/cts/KeyValueQuotaTest.java
new file mode 100644
index 0000000..c29f810
--- /dev/null
+++ b/tests/backup/src/android/backup/cts/KeyValueQuotaTest.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 android.backup.cts;
+
+/**
+ * Verifies receiving quotaExceeded() callback on full backup.
+ *
+ * Uses test app that creates large file and receives the callback.
+ * {@link com.android.internal.backup.LocalTransport} is used, it has size quota 25MB.
+ */
+public class KeyValueQuotaTest extends BaseBackupCtsTest {
+
+    private static final String BACKUP_APP_NAME = "android.backup.kvapp";
+
+    // Should be the same as LocalTransport. KEY_VALUE_BACKUP_SIZE_QUOTA
+    private static final int LOCAL_TRANSPORT_BACKUP_QUOTA = 5 * 1024 * 1024;
+    private static final int LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE = 6 * 1024 * 1024;
+
+    private static final int TIMEOUT_SECONDS = 30;
+
+    public void testQuotaExceeded() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        String separator = clearLogcat();
+        // Launch test app and create file exceeding limit for local transport
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE);
+
+        // Request backup and wait for quota exceeded event in logcat
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+        waitForLogcat(TIMEOUT_SECONDS, separator,
+            "Quota exceeded!");
+    }
+
+    public void testQuotaReported() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        String separator = clearLogcat();
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+        waitForLogcat(TIMEOUT_SECONDS, separator,
+            "quota is " + LOCAL_TRANSPORT_BACKUP_QUOTA);
+    }
+
+}
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index d6331e76..c8ba9cd 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -58,7 +58,7 @@
 	$(call all-renderscript-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsCameraTestCases
 
diff --git a/tests/camera/api25test/Android.mk b/tests/camera/api25test/Android.mk
index f757491..a848031 100644
--- a/tests/camera/api25test/Android.mk
+++ b/tests/camera/api25test/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/dram/Android.mk b/tests/dram/Android.mk
index 5c44668..1d21cdc 100644
--- a/tests/dram/Android.mk
+++ b/tests/dram/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_PACKAGE_NAME := CtsDramTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := 16
 
diff --git a/tests/dram/jni/Android.mk b/tests/dram/jni/Android.mk
index 4469cc4..1021aaa 100644
--- a/tests/dram/jni/Android.mk
+++ b/tests/dram/jni/Android.mk
@@ -26,4 +26,6 @@
 
 LOCAL_SDK_VERSION := 14
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/filesystem/Android.mk b/tests/filesystem/Android.mk
index 97f24b0..9dca6af 100644
--- a/tests/filesystem/Android.mk
+++ b/tests/filesystem/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_PACKAGE_NAME := CtsFileSystemTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := 16
 
diff --git a/tests/fragment/Android.mk b/tests/fragment/Android.mk
index 0225b21..1785097 100644
--- a/tests/fragment/Android.mk
+++ b/tests/fragment/Android.mk
@@ -40,7 +40,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/fragment/AndroidTest.xml b/tests/fragment/AndroidTest.xml
index 690bdc2..4e563d9 100644
--- a/tests/fragment/AndroidTest.xml
+++ b/tests/fragment/AndroidTest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Configuration for app.usage Tests">
-    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsFragmentTestCases.apk" />
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index 00ec95b..c1fd9d8 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -46,6 +46,7 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Pair;
 import android.view.LayoutInflater;
+import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -956,6 +957,112 @@
         });
     }
 
+    @Test
+    public void optionsMenu() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, null);
+            FragmentManager fm = fc.getFragmentManager();
+
+            InvalidateOptionFragment fragment = new InvalidateOptionFragment();
+            fm.beginTransaction()
+                    .add(android.R.id.content, fragment)
+                    .commit();
+            fm.executePendingTransactions();
+
+            Menu menu = mock(Menu.class);
+            fc.dispatchPrepareOptionsMenu(menu);
+            assertTrue(fragment.onPrepareOptionsMenuCalled);
+            fragment.onPrepareOptionsMenuCalled = false;
+            FragmentTestUtil.destroy(mActivityRule, fc);
+            fc.dispatchPrepareOptionsMenu(menu);
+            assertFalse(fragment.onPrepareOptionsMenuCalled);
+        });
+    }
+
+
+    /**
+     * When a retained instance fragment is saved while in the back stack, it should go
+     * through onCreate() when it is popped back.
+     */
+    @Test
+    public void retainInstanceWithOnCreate() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, null);
+            FragmentManager fm = fc.getFragmentManager();
+
+            OnCreateFragment fragment1 = new OnCreateFragment();
+
+            fm.beginTransaction()
+                    .add(fragment1, "1")
+                    .commit();
+            fm.beginTransaction()
+                    .remove(fragment1)
+                    .addToBackStack(null)
+                    .commit();
+
+            Pair<Parcelable, FragmentManagerNonConfig> savedState =
+                    FragmentTestUtil.destroy(mActivityRule, fc);
+            Pair<Parcelable, FragmentManagerNonConfig> restartState =
+                    Pair.create(savedState.first, null);
+
+            fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, restartState);
+
+            // Save again, but keep the state
+            savedState = FragmentTestUtil.destroy(mActivityRule, fc);
+
+            fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, savedState);
+
+            fm = fc.getFragmentManager();
+
+            fm.popBackStackImmediate();
+            OnCreateFragment fragment2 = (OnCreateFragment) fm.findFragmentByTag("1");
+            assertTrue(fragment2.onCreateCalled);
+            fm.popBackStackImmediate();
+        });
+    }
+
+    /**
+     * A retained instance fragment should go through onCreate() once, even through save and
+     * restore.
+     */
+    @Test
+    public void retainInstanceOneOnCreate() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, null);
+            FragmentManager fm = fc.getFragmentManager();
+
+            OnCreateFragment fragment = new OnCreateFragment();
+
+            fm.beginTransaction()
+                    .add(fragment, "fragment")
+                    .commit();
+            fm.executePendingTransactions();
+
+            fm.beginTransaction()
+                    .remove(fragment)
+                    .addToBackStack(null)
+                    .commit();
+
+            assertTrue(fragment.onCreateCalled);
+            fragment.onCreateCalled = false;
+
+            Pair<Parcelable, FragmentManagerNonConfig> savedState =
+                    FragmentTestUtil.destroy(mActivityRule, fc);
+
+            fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, savedState);
+            fm = fc.getFragmentManager();
+
+            fm.popBackStackImmediate();
+            assertFalse(fragment.onCreateCalled);
+        });
+    }
+
     private void executePendingTransactions(final FragmentManager fm) throws Throwable {
         mActivityRule.runOnUiThread(new Runnable() {
             @Override
@@ -1162,4 +1269,33 @@
             }
         }
     }
+
+    public static class InvalidateOptionFragment extends Fragment {
+        public boolean onPrepareOptionsMenuCalled;
+
+        public InvalidateOptionFragment() {
+            setHasOptionsMenu(true);
+        }
+
+        @Override
+        public void onPrepareOptionsMenu(Menu menu) {
+            onPrepareOptionsMenuCalled = true;
+            assertNotNull(getContext());
+            super.onPrepareOptionsMenu(menu);
+        }
+    }
+
+    public static class OnCreateFragment extends Fragment {
+        public boolean onCreateCalled;
+
+        public OnCreateFragment() {
+            setRetainInstance(true);
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            onCreateCalled = true;
+        }
+    }
 }
diff --git a/tests/fragment/src/android/fragment/cts/LoaderActivity.java b/tests/fragment/src/android/fragment/cts/LoaderActivity.java
index 9c69f75..b1a8add 100644
--- a/tests/fragment/src/android/fragment/cts/LoaderActivity.java
+++ b/tests/fragment/src/android/fragment/cts/LoaderActivity.java
@@ -23,6 +23,8 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import java.util.concurrent.CountDownLatch;
+
 /**
  * This Activity sets the text when loading completes. It also tracks the Activity in
  * a static variable, so it must be cleared in test tear down.
@@ -30,6 +32,7 @@
 public class LoaderActivity extends RecreatedActivity {
     public TextView textView;
     public TextView textViewB;
+    public CountDownLatch loadFinished = new CountDownLatch(1);
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -59,6 +62,7 @@
         @Override
         public void onLoadFinished(Loader<String> loader, String data) {
             textView.setText(data);
+            loadFinished.countDown();
         }
 
         @Override
@@ -82,3 +86,4 @@
         }
     }
 }
+
diff --git a/tests/fragment/src/android/fragment/cts/LoaderTest.java b/tests/fragment/src/android/fragment/cts/LoaderTest.java
index 2eb897e..fbf4258 100755
--- a/tests/fragment/src/android/fragment/cts/LoaderTest.java
+++ b/tests/fragment/src/android/fragment/cts/LoaderTest.java
@@ -96,10 +96,13 @@
     @Test
     public void startWhenReused() throws Throwable {
         LoaderActivity activity = mActivityRule.getActivity();
+        activity.waitForResume(mActivityRule);
+        assertTrue(activity.loadFinished.await(1, TimeUnit.SECONDS));
 
         assertEquals("Loaded!", activity.textView.getText().toString());
 
         activity = FragmentTestUtil.recreateActivity(mActivityRule, activity);
+        assertTrue(activity.loadFinished.await(1, TimeUnit.SECONDS));
 
         // After orientation change, the text should still be loaded properly
         assertEquals("Loaded!", activity.textView.getText().toString());
diff --git a/tests/fragment/src/android/fragment/cts/RecreatedActivity.java b/tests/fragment/src/android/fragment/cts/RecreatedActivity.java
index 82b32a9..833d532 100644
--- a/tests/fragment/src/android/fragment/cts/RecreatedActivity.java
+++ b/tests/fragment/src/android/fragment/cts/RecreatedActivity.java
@@ -15,16 +15,21 @@
  */
 package android.fragment.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
 import android.os.Bundle;
+import android.support.test.rule.ActivityTestRule;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
-public class RecreatedActivity extends Activity {
+public class RecreatedActivity extends FragmentTestActivity {
     // These must be cleared after each test using clearState()
     public static RecreatedActivity sActivity;
     public static CountDownLatch sResumed;
     public static CountDownLatch sDestroyed;
+    private boolean mIsResumed;
 
     public static void clearState() {
         sActivity = null;
@@ -41,15 +46,42 @@
     @Override
     protected void onResume() {
         super.onResume();
+        mIsResumed = true;
         if (sResumed != null) {
             sResumed.countDown();
         }
     }
 
     @Override
+    protected void onPause() {
+        super.onPause();
+        mIsResumed = false;
+    }
+
+    @Override
     protected void onDestroy() {
         super.onDestroy();
         if (sDestroyed != null) {
             sDestroyed.countDown();
         }
-    }}
+    }
+
+    public void waitForResume(ActivityTestRule<? extends Activity> rule) throws Throwable {
+        if (mIsResumed) {
+            return;
+        }
+        if (sResumed != null) {
+            assertTrue(sResumed.await(1, TimeUnit.SECONDS));
+        } else {
+            rule.runOnUiThread(() -> {
+                if (!mIsResumed) {
+                    sResumed = new CountDownLatch(1);
+                }
+            });
+            if (sResumed != null) {
+                assertTrue(sResumed.await(1, TimeUnit.SECONDS));
+                sResumed = null;
+            }
+        }
+    }
+}
diff --git a/tests/inputmethod/Android.mk b/tests/inputmethod/Android.mk
index 5093e6f..0c1ed5f 100644
--- a/tests/inputmethod/Android.mk
+++ b/tests/inputmethod/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MULTILIB := both
 
diff --git a/tests/jank/Android.mk b/tests/jank/Android.mk
index 8e2348b..16954f2 100644
--- a/tests/jank/Android.mk
+++ b/tests/jank/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_PACKAGE_NAME := CtsJankDeviceTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     compatibility-device-util \
diff --git a/tests/jdwp/Android.mk b/tests/jdwp/Android.mk
index da4ea38..648e4ea 100644
--- a/tests/jdwp/Android.mk
+++ b/tests/jdwp/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_MODULE_TAGS := optional
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_JAVA_LIBRARY)
 
diff --git a/tests/jdwp/runner/device-side/Android.mk b/tests/jdwp/runner/device-side/Android.mk
index f04bf4a..fa7b294 100644
--- a/tests/jdwp/runner/device-side/Android.mk
+++ b/tests/jdwp/runner/device-side/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_MODULE_TAGS := optional
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_JAVA_LIBRARY)
diff --git a/tests/jdwp/runner/host-side/Android.mk b/tests/jdwp/runner/host-side/Android.mk
index 702174c..32abf79 100644
--- a/tests/jdwp/runner/host-side/Android.mk
+++ b/tests/jdwp/runner/host-side/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_JAVA_RESOURCE_DIRS := resources
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/leanbackjank/Android.mk b/tests/leanbackjank/Android.mk
index 5b5f053..ec114f3 100644
--- a/tests/leanbackjank/Android.mk
+++ b/tests/leanbackjank/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsLeanbackJankTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     compatibility-device-util \
diff --git a/tests/leanbackjank/app/Android.mk b/tests/leanbackjank/app/Android.mk
index 3925c2a..3fc685d 100644
--- a/tests/leanbackjank/app/Android.mk
+++ b/tests/leanbackjank/app/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_PACKAGE_NAME := CtsLeanbackJankApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_RESOURCE_DIR := \
     $(TOP)/frameworks/support/v17/leanback/res \
diff --git a/tests/libcore/javautilcollections/Android.mk b/tests/libcore/javautilcollections/Android.mk
index fc90888..e2bcef5 100644
--- a/tests/libcore/javautilcollections/Android.mk
+++ b/tests/libcore/javautilcollections/Android.mk
@@ -29,6 +29,6 @@
     guava-testlib-20.0-prebuilt
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_PACKAGE_NAME := CtsLibcoreJavaUtilCollectionsTestCases
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/libcore/jsr166/Android.mk b/tests/libcore/jsr166/Android.mk
index 2a9b870..9e11815 100644
--- a/tests/libcore/jsr166/Android.mk
+++ b/tests/libcore/jsr166/Android.mk
@@ -34,7 +34,7 @@
 LOCAL_PROGUARD_ENABLED := disabled
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
 
diff --git a/tests/libcore/luni/Android.mk b/tests/libcore/luni/Android.mk
index 7b5d733..81b44d3 100644
--- a/tests/libcore/luni/Android.mk
+++ b/tests/libcore/luni/Android.mk
@@ -24,8 +24,8 @@
     core-tests \
     cts-core-test-runner \
     mockito-target-minus-junit4 \
-    tzdata_shared2-tests \
-    tzdata_update2-tests
+    time_zone_distro-tests \
+    time_zone_distro_installer-tests
 
 # Don't include this package in any target
 LOCAL_MODULE_TAGS := tests
@@ -38,7 +38,8 @@
 LOCAL_DX_FLAGS := --multi-dex
 
 LOCAL_PROGUARD_ENABLED := disabled
-
+# Keep META-INF/ resources from LOCAL_STATIC_JAVA_LIBRARIES. http://b/62341677
+LOCAL_DONT_DELETE_JAR_META_INF := true
 LOCAL_JNI_SHARED_LIBRARIES := libjavacoretests libsqlite_jni libnativehelper_compat_libc++ libc++
 
 # Include both the 32 and 64 bit versions of libjavacoretests,
@@ -46,7 +47,7 @@
 LOCAL_MULTILIB := both
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # NOTE: virtualdeviceknownfailures.txt is only used for simulated/cloud-based
 # continuous build configurations, so it's not referenced in AndroidTest.xml
diff --git a/tests/libcore/ojluni/Android.mk b/tests/libcore/ojluni/Android.mk
index a6e378f..be709be 100644
--- a/tests/libcore/ojluni/Android.mk
+++ b/tests/libcore/ojluni/Android.mk
@@ -30,6 +30,9 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_JACK_FLAGS := --multi-dex native
 
+# Keep META-INF/ resources from LOCAL_STATIC_JAVA_LIBRARIES. http://b/62231394
+LOCAL_DONT_DELETE_JAR_META_INF := true
+
 LOCAL_PROGUARD_ENABLED := disabled
 
 # Include both the 32 and 64 bit versions of libjavacoretests,
@@ -37,7 +40,7 @@
 LOCAL_MULTILIB := both
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
 
diff --git a/tests/libcore/okhttp/Android.mk b/tests/libcore/okhttp/Android.mk
index 98ed152..91e9ef5 100644
--- a/tests/libcore/okhttp/Android.mk
+++ b/tests/libcore/okhttp/Android.mk
@@ -40,7 +40,7 @@
 LOCAL_MULTILIB := both
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
 
diff --git a/tests/libcore/runner/Android.mk b/tests/libcore/runner/Android.mk
index 3b20cfa..6ef3c03 100644
--- a/tests/libcore/runner/Android.mk
+++ b/tests/libcore/runner/Android.mk
@@ -33,6 +33,6 @@
 LOCAL_PROGUARD_ENABLED := disabled
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/wycheproof-bc/Android.mk b/tests/libcore/wycheproof-bc/Android.mk
new file mode 100644
index 0000000..801feac
--- /dev/null
+++ b/tests/libcore/wycheproof-bc/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofBCTestCases
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    cts-core-test-runner \
+    wycheproof
+
+LOCAL_JAVA_LIBRARIES := bouncycastle
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+LOCAL_DEX_PREOPT := false
+LOCAL_JACK_FLAGS := --multi-dex native
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+# Include both the 32 and 64 bit versions of libjavacoretests,
+# where applicable.
+LOCAL_MULTILIB := both
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts
+
+LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/vm-tests-tf/AndroidManifest.xml b/tests/libcore/wycheproof-bc/AndroidManifest.xml
similarity index 69%
rename from tests/vm-tests-tf/AndroidManifest.xml
rename to tests/libcore/wycheproof-bc/AndroidManifest.xml
index 2a2f40a..15c5fd5 100644
--- a/tests/vm-tests-tf/AndroidManifest.xml
+++ b/tests/libcore/wycheproof-bc/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2007 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.
@@ -15,15 +15,14 @@
  * limitations under the License.
  -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.core.vm-tests-tf">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.libcore.cts.wycheproof.bouncycastle">
     <uses-permission android:name="android.permission.INTERNET" />
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationCoreTestRunner"
-                     android:targetPackage="android.core.vm-tests-tf"
-                     android:label="cts trade federation vm tests"/>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.libcore.cts.wycheproof.bouncycastle"
+                     android:label="CTS Libcore Wycheproof Bouncy Castle test cases" />
 
 </manifest>
diff --git a/tests/libcore/wycheproof-bc/AndroidTest.xml b/tests/libcore/wycheproof-bc/AndroidTest.xml
new file mode 100644
index 0000000..9c3a50a
--- /dev/null
+++ b/tests/libcore/wycheproof-bc/AndroidTest.xml
@@ -0,0 +1,36 @@
+<?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 Libcore Wycheproof Bouncy Castle test cases">
+    <option name="config-descriptor:metadata" key="component" value="libcore" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <!-- this has just the instrumentation which acts as the tests we want to run -->
+        <option name="test-file-name" value="CtsLibcoreWycheproofBCTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.testtype.LibcoreTest" >
+        <option name="package" value="android.libcore.cts.wycheproof.bouncycastle" />
+        <!-- The individual test cases don't work unless they're run in the
+             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" />
+        <option name="runtime-hint" value="10m"/>
+    </test>
+</configuration>
diff --git a/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleSupportProvider.java b/tests/libcore/wycheproof-bc/src/android/libcore/cts/wycheproof/BouncyCastleSupportProvider.java
similarity index 100%
rename from tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleSupportProvider.java
rename to tests/libcore/wycheproof-bc/src/android/libcore/cts/wycheproof/BouncyCastleSupportProvider.java
diff --git a/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleTest.java b/tests/libcore/wycheproof-bc/src/android/libcore/cts/wycheproof/BouncyCastleTest.java
similarity index 100%
rename from tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleTest.java
rename to tests/libcore/wycheproof-bc/src/android/libcore/cts/wycheproof/BouncyCastleTest.java
diff --git a/tests/libcore/wycheproof/Android.mk b/tests/libcore/wycheproof/Android.mk
index c14da89..652e36c 100644
--- a/tests/libcore/wycheproof/Android.mk
+++ b/tests/libcore/wycheproof/Android.mk
@@ -16,15 +16,13 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofTestCases
+LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofConscryptTestCases
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     cts-core-test-runner \
     wycheproof
 
-LOCAL_JAVA_LIBRARIES := \
-    bouncycastle \
-    conscrypt
+LOCAL_JAVA_LIBRARIES := conscrypt
 
 # Don't include this package in any target
 LOCAL_MODULE_TAGS := tests
@@ -44,7 +42,7 @@
 LOCAL_MULTILIB := both
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
 
diff --git a/tests/libcore/wycheproof/AndroidManifest.xml b/tests/libcore/wycheproof/AndroidManifest.xml
index 09b9da1..765c677 100644
--- a/tests/libcore/wycheproof/AndroidManifest.xml
+++ b/tests/libcore/wycheproof/AndroidManifest.xml
@@ -15,14 +15,14 @@
  * limitations under the License.
  -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.libcore.cts.wycheproof">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.libcore.cts.wycheproof.conscrypt">
     <uses-permission android:name="android.permission.INTERNET" />
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.libcore.cts.wycheproof"
-                     android:label="CTS Libcore Wycheproof test cases" />
+                     android:targetPackage="android.libcore.cts.wycheproof.conscrypt"
+                     android:label="CTS Libcore Wycheproof Conscrypt test cases" />
 
 </manifest>
diff --git a/tests/libcore/wycheproof/AndroidTest.xml b/tests/libcore/wycheproof/AndroidTest.xml
index 2d303d2..b5874fd 100644
--- a/tests/libcore/wycheproof/AndroidTest.xml
+++ b/tests/libcore/wycheproof/AndroidTest.xml
@@ -13,15 +13,15 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Libcore Wycheproof test cases">
+<configuration description="Config for CTS Libcore Wycheproof Conscrypt test cases">
     <option name="config-descriptor:metadata" key="component" value="libcore" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <!-- this has just the instrumentation which acts as the tests we want to run -->
-        <option name="test-file-name" value="CtsLibcoreWycheproofTestCases.apk" />
+        <option name="test-file-name" value="CtsLibcoreWycheproofConscryptTestCases.apk" />
     </target_preparer>
     <test class="com.android.compatibility.testtype.LibcoreTest" >
-        <option name="package" value="android.libcore.cts.wycheproof" />
+        <option name="package" value="android.libcore.cts.wycheproof.conscrypt" />
         <!-- The individual test cases don't work unless they're run in the
              context of one of the suites, so we have to limit the test
              infrastructure to only running the test suites. -->
diff --git a/tests/netlegacy22.api/Android.mk b/tests/netlegacy22.api/Android.mk
index 836bd9b..86395142 100644
--- a/tests/netlegacy22.api/Android.mk
+++ b/tests/netlegacy22.api/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/netlegacy22.permission/Android.mk b/tests/netlegacy22.permission/Android.mk
index 2f9221d..262e600 100644
--- a/tests/netlegacy22.permission/Android.mk
+++ b/tests/netlegacy22.permission/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/netsecpolicy/usescleartexttraffic-false/Android.mk b/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
index 847d5ec..34422f8 100644
--- a/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
+++ b/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficFalse
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/netsecpolicy/usescleartexttraffic-true/Android.mk b/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
index 95da495..efabeb2 100644
--- a/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
+++ b/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficTrue
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk b/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
index 009b3fc..9960bca 100644
--- a/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
+++ b/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficUnspecified
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/openglperf2/Android.mk b/tests/openglperf2/Android.mk
index 0a87b05..4f402ca 100644
--- a/tests/openglperf2/Android.mk
+++ b/tests/openglperf2/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_PACKAGE_NAME := CtsOpenGlPerf2TestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := 16
 
diff --git a/tests/openglperf2/jni/Android.mk b/tests/openglperf2/jni/Android.mk
index c2bb7a8..174375d 100644
--- a/tests/openglperf2/jni/Android.mk
+++ b/tests/openglperf2/jni/Android.mk
@@ -21,6 +21,8 @@
 # Needed in order to use fences for synchronization
 LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -funsigned-char
 
+LOCAL_CFLAGS += -Wno-unused-parameter
+
 # Get all cpp files but not hidden files
 LOCAL_SRC_FILES := $(call all-subdir-cpp-files)
 
diff --git a/tests/pdf/Android.mk b/tests/pdf/Android.mk
index 3a7e2a0..2b301af 100644
--- a/tests/pdf/Android.mk
+++ b/tests/pdf/Android.mk
@@ -34,7 +34,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsPdfTestCases
 
diff --git a/tests/sample/Android.mk b/tests/sample/Android.mk
index fe790c7..f6d8760 100755
--- a/tests/sample/Android.mk
+++ b/tests/sample/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsSampleDeviceTestCases
 
diff --git a/tests/sensor/Android.mk b/tests/sensor/Android.mk
index 0928579..dcf9015 100644
--- a/tests/sensor/Android.mk
+++ b/tests/sensor/Android.mk
@@ -73,7 +73,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
diff --git a/tests/sensor/jni/android_hardware_cts_SensorDirectReportTest.cpp b/tests/sensor/jni/android_hardware_cts_SensorDirectReportTest.cpp
index f189cf9..efb5f33 100644
--- a/tests/sensor/jni/android_hardware_cts_SensorDirectReportTest.cpp
+++ b/tests/sensor/jni/android_hardware_cts_SensorDirectReportTest.cpp
@@ -46,8 +46,8 @@
     if (AHardwareBuffer_lock(hardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
                              fence, nullptr, &address) == 0) {
         if (address != nullptr) {
-            env->SetByteArrayRegion(
-                    buffer, destOffset, count, reinterpret_cast<const jbyte *>(address));
+            env->SetByteArrayRegion(buffer, destOffset, count,
+                                    reinterpret_cast<const jbyte *>(address) + srcOffset);
             ret = true;
         } else {
             ALOGE("AHardwareBuffer locked but address is invalid");
diff --git a/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java b/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
index 78ac59d..fd3935d 100644
--- a/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
@@ -22,15 +22,21 @@
 import android.hardware.SensorAdditionalInfo;
 import android.hardware.SensorDirectChannel;
 import android.hardware.SensorEventCallback;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.hardware.cts.helpers.SensorCtsHelper;
+import android.hardware.cts.helpers.SensorCtsHelper.TestResultCollector;
 import android.os.MemoryFile;
+import android.os.SystemClock;
 import android.util.Log;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -43,6 +49,27 @@
  *   - SensorDirectChannel.*
  *   - Sensor.getHighestDirectReportRateLevel()
  *   - Sensor.isDirectChannelTypeSupported()
+ *
+ * Tests:
+ *   - test<Sensor><SharedMemoryType><RateLevel>
+ *     tests basic operation of sensor in direct report mode at various rate level specification.
+ *   - testRateIndependency<Sensor1><Sensor2>SingleChannel
+ *     tests if two sensors in the same direct channel are able to run at different rates.
+ *   - testRateIndependency<Sensor>MultiChannel
+ *     tests if a sensor is able to be configured to different rate levels for multiple channels.
+ *   - testRateIndependency<Sensor>MultiMode
+ *     tests if a sensor is able to report at different rates in direct report mode and traditional
+ *     report mode (polling).
+ *   - testTimestamp<Sensor>
+ *     tests if the timestamp is correct both in absolute sense and relative to traditional report.
+ *   - testAtomicCounter<Sensor>
+ *     test if atomic counter is increased as specified and if sensor event content is fully updated
+ *     before update of atomic counter.
+ *   - testRegisterMultipleChannels
+ *     test scenarios when multiple channels are registered simultaneously.
+ *   - testReconfigure
+ *     test channel reconfiguration (configure to a rate level; configure to stop; configure to
+ *     another rate level)
  */
 public class SensorDirectReportTest extends SensorTestCase {
     private static final String TAG = "SensorDirectReportTest";
@@ -55,9 +82,13 @@
     private static final float FREQ_LOWER_BOUND = 0.55f;
     private static final float FREQ_UPPER_BOUND = 2.2f;
 
+    // actuall value is allowed to be 90% to 200% of nominal value in poll() interface
+    private static final float FREQ_LOWER_BOUND_POLL = 0.90f;
+    private static final float FREQ_UPPER_BOUND_POLL = 2.00f;
+
     // sensor reading assumption
-    private static final float GRAVITY_MIN = 9.81f - 0.5f;
-    private static final float GRAVITY_MAX = 9.81f + 0.5f;
+    private static final float GRAVITY_MIN = 9.81f - 1.0f;
+    private static final float GRAVITY_MAX = 9.81f + 1.0f;
     private static final float GYRO_NORM_MAX = 0.1f;
 
     // test constants
@@ -65,21 +96,61 @@
     private static final int TEST_RUN_TIME_PERIOD_MILLISEC = 5000;
     private static final int ALLOWED_SENSOR_INIT_TIME_MILLISEC = 500;
     private static final int SENSORS_EVENT_SIZE = 104;
+    private static final int ATOMIC_COUNTER_OFFSET = 12;
+    private static final int ATOMIC_COUNTER_SIZE = 4;
     private static final int SENSORS_EVENT_COUNT = 10240; // 800Hz * 2.2 * 5 sec + extra
     private static final int SHARED_MEMORY_SIZE = SENSORS_EVENT_COUNT * SENSORS_EVENT_SIZE;
     private static final float MERCY_FACTOR = 0.1f;
+    private static final boolean CHECK_ABSOLUTE_LATENCY = false;
+
+    // list of rate levels being tested
+    private static final int[] POSSIBLE_RATE_LEVELS = new int[] {
+            SensorDirectChannel.RATE_NORMAL,
+            SensorDirectChannel.RATE_FAST,
+            SensorDirectChannel.RATE_VERY_FAST
+        };
+
+    // list of channel types being tested
+    private static final int[] POSSIBLE_CHANNEL_TYPES = new int [] {
+            SensorDirectChannel.TYPE_MEMORY_FILE,
+            SensorDirectChannel.TYPE_HARDWARE_BUFFER
+        };
+
+    // list of sensor types being tested
+    private static final int[] POSSIBLE_SENSOR_TYPES = new int [] {
+            Sensor.TYPE_ACCELEROMETER,
+            Sensor.TYPE_GYROSCOPE,
+            Sensor.TYPE_MAGNETIC_FIELD
+        };
+
+    // list of sampling period being tested
+    private static final int[] POSSIBLE_SAMPLE_PERIOD_US = new int [] {
+            200_000, // Normal 5 Hz
+            66_667,  // UI    15 Hz
+            20_000,  // Game  50 Hz
+            5_000,   // 200Hz
+            0        // fastest
+        };
+
+    private static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();
 
     private static native boolean nativeReadHardwareBuffer(HardwareBuffer hardwareBuffer,
             byte[] buffer, int srcOffset, int destOffset, int count);
 
     private boolean mNeedMemoryFile;
     private MemoryFile mMemoryFile;
+    private MemoryFile mMemoryFileSecondary;
     private boolean mNeedHardwareBuffer;
     private HardwareBuffer mHardwareBuffer;
-    private byte[] mBuffer = new byte[SHARED_MEMORY_SIZE];
+    private HardwareBuffer mHardwareBufferSecondary;
+    private ByteBuffer mByteBuffer;
+    private byte[] mBuffer;
 
     private SensorManager mSensorManager;
     private SensorDirectChannel mChannel;
+    private SensorDirectChannel mChannelSecondary;
+
+    private EventPool mEventPool;
 
     static {
         System.loadLibrary("cts-sensors-ndk-jni");
@@ -87,18 +158,19 @@
 
     @Override
     protected void setUp() throws Exception {
+        super.setUp();
+
+        mByteBuffer = ByteBuffer.allocate(SHARED_MEMORY_SIZE);
+        mBuffer = mByteBuffer.array();
+        mByteBuffer.order(ByteOrder.nativeOrder());
+
+        mEventPool = new EventPool(10 * SENSORS_EVENT_COUNT);
         mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
 
         mNeedMemoryFile = isMemoryTypeNeeded(SensorDirectChannel.TYPE_MEMORY_FILE);
         mNeedHardwareBuffer = isMemoryTypeNeeded(SensorDirectChannel.TYPE_HARDWARE_BUFFER);
 
-        if (mNeedMemoryFile) {
-            mMemoryFile = allocateMemoryFile();
-        }
-
-        if (mNeedHardwareBuffer) {
-            mHardwareBuffer = allocateHardwareBuffer();
-        }
+        allocateSharedMemory();
     }
 
     @Override
@@ -108,22 +180,23 @@
             mChannel = null;
         }
 
-        if (mMemoryFile != null) {
-            mMemoryFile.close();
-            mMemoryFile = null;
+        if (mChannelSecondary != null) {
+            mChannelSecondary.close();
+            mChannelSecondary = null;
         }
 
-        if (mHardwareBuffer != null) {
-            mHardwareBuffer.close();
-            mHardwareBuffer = null;
-        }
+        freeSharedMemory();
+        super.tearDown();
     }
 
     public void testSharedMemoryAllocation() throws AssertionError {
-        assertTrue("allocating MemoryFile returned null",
-                !mNeedMemoryFile || mMemoryFile != null);
-        assertTrue("allocating HardwareBuffer returned null",
-                !mNeedHardwareBuffer || mHardwareBuffer != null);
+        assertTrue("allocating MemoryFile returned null: "
+                        + (mMemoryFile == null) + ", " + (mMemoryFileSecondary == null),
+                   !mNeedMemoryFile || (mMemoryFile != null && mMemoryFileSecondary != null));
+        assertTrue("allocating HardwareBuffer returned null: "
+                        + (mHardwareBuffer == null) + ", " + (mHardwareBufferSecondary == null),
+                   !mNeedHardwareBuffer ||
+                       (mHardwareBuffer != null && mHardwareBufferSecondary != null));
     }
 
     public void testAccelerometerAshmemNormal() {
@@ -254,6 +327,226 @@
                 SensorDirectChannel.RATE_VERY_FAST);
     }
 
+    public void testRateIndependencyAccelGyroSingleChannel() {
+        runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER,
+                                                  Sensor.TYPE_GYROSCOPE);
+    }
+
+    public void testRateIndependencyAccelMagSingleChannel() {
+        runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER,
+                                                  Sensor.TYPE_MAGNETIC_FIELD);
+    }
+
+    public void testRateIndependencyGyroMagSingleChannel() {
+        runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE,
+                                                  Sensor.TYPE_MAGNETIC_FIELD);
+    }
+
+    public void testRateIndependencyAccelUncalAccelSingleChannel() {
+        runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER,
+                                             Sensor.TYPE_ACCELEROMETER_UNCALIBRATED);
+    }
+
+    public void testRateIndependencyGyroUncalGyroSingleChannel() {
+        runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE,
+                                             Sensor.TYPE_GYROSCOPE_UNCALIBRATED);
+    }
+
+    public void testRateIndependencyMagUncalMagSingleChannel() {
+        runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_MAGNETIC_FIELD,
+                                             Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);
+    }
+
+    public void testRateIndependencyAccelMultiChannel() {
+        runMultiChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER);
+    }
+
+    public void testRateIndependencyGyroMultiChannel() {
+        runMultiChannelRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE);
+    }
+
+    public void testRateIndependencyMagMultiChannel() {
+        runMultiChannelRateIndependencyTestGroup(Sensor.TYPE_MAGNETIC_FIELD);
+    }
+
+    public void testRateIndependencyAccelMultiMode() {
+        runMultiModeRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER);
+    }
+
+    public void testRateIndependencyGyroMultiMode() {
+        runMultiModeRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE);
+    }
+
+    public void testRateIndependencyMagMultiMode() {
+        runMultiModeRateIndependencyTestGroup(Sensor.TYPE_MAGNETIC_FIELD);
+    }
+
+    public void testTimestampAccel() {
+        runTimestampTestGroup(Sensor.TYPE_ACCELEROMETER);
+    }
+
+    public void testTimestampGyro() {
+        runTimestampTestGroup(Sensor.TYPE_GYROSCOPE);
+    }
+
+    public void testTimestampMag() {
+        runTimestampTestGroup(Sensor.TYPE_MAGNETIC_FIELD);
+    }
+
+    public void testAtomicCounterAccel() {
+        for (int memType : POSSIBLE_CHANNEL_TYPES) {
+            runAtomicCounterTest(Sensor.TYPE_ACCELEROMETER, memType);
+        }
+    }
+
+    public void testAtomicCounterGyro() {
+        for (int memType : POSSIBLE_CHANNEL_TYPES) {
+            runAtomicCounterTest(Sensor.TYPE_GYROSCOPE, memType);
+        }
+    }
+
+    public void testAtomicCounterMag() {
+        for (int memType : POSSIBLE_CHANNEL_TYPES) {
+            runAtomicCounterTest(Sensor.TYPE_MAGNETIC_FIELD, memType);
+        }
+    }
+
+    public void testRegisterMultipleChannels() throws AssertionError {
+        resetEvent();
+        freeSharedMemory();
+
+        for (int memType : POSSIBLE_CHANNEL_TYPES) {
+            if (!isMemoryTypeNeeded(memType)) {
+                continue;
+            }
+
+            for (int repeat = 0; repeat < 10; ++repeat) {
+                // allocate new memory every time
+                allocateSharedMemory();
+
+                mChannel = prepareDirectChannel(memType, false /* secondary */);
+                assertNotNull("mChannel is null", mChannel);
+
+                mChannelSecondary = prepareDirectChannel(memType, true /* secondary */);
+                assertNotNull("mChannelSecondary is null", mChannelSecondary);
+
+                if (mChannel != null) {
+                    mChannel.close();
+                    mChannel = null;
+                }
+                if (mChannelSecondary != null) {
+                    mChannelSecondary.close();
+                    mChannelSecondary = null;
+                }
+
+                // free shared memory
+                freeSharedMemory();
+            }
+        }
+    }
+
+    public void testReconfigure() {
+        TestResultCollector c = new TestResultCollector("testReconfigure", TAG);
+
+        for (int type : POSSIBLE_SENSOR_TYPES) {
+            for (int memType : POSSIBLE_CHANNEL_TYPES) {
+                c.perform(() -> { runReconfigureTest(type, memType);},
+                        String.format("sensor type %d, mem type %d", type, memType));
+            }
+        }
+        c.judge();
+    }
+
+    private void runSingleChannelRateIndependencyTestGroup(int type1, int type2) {
+        if (type1 == type2) {
+            throw new IllegalArgumentException("Cannot run single channel rate independency test "
+                    + "on type " + type1 + " and " + type2);
+        }
+        String stype1 = SensorCtsHelper.sensorTypeShortString(type1);
+        String stype2 = SensorCtsHelper.sensorTypeShortString(type2);
+
+        TestResultCollector c =
+                new TestResultCollector(
+                    "testRateIndependency" + stype1 + stype2 + "SingleChannel", TAG);
+
+        for (int rate1 : POSSIBLE_RATE_LEVELS) {
+            for (int rate2 : POSSIBLE_RATE_LEVELS) {
+                for (int memType : POSSIBLE_CHANNEL_TYPES) {
+                    c.perform(
+                        () -> {
+                            runSingleChannelRateIndependencyTest(
+                                    type1, rate1, type2, rate2,
+                                    SensorDirectChannel.TYPE_MEMORY_FILE);
+                        },
+                        String.format("(%s rate %d, %s rate %d, mem %d)",
+                                      stype1, rate1, stype2, rate2, memType));
+                }
+            }
+        }
+        c.judge();
+    }
+
+    public void runMultiChannelRateIndependencyTestGroup(int sensorType) {
+        TestResultCollector c = new TestResultCollector(
+                "testRateIndependency" + SensorCtsHelper.sensorTypeShortString(sensorType)
+                    + "MultiChannel", TAG);
+
+        for (int rate1 : POSSIBLE_RATE_LEVELS) {
+            for (int rate2 : POSSIBLE_RATE_LEVELS) {
+                for (int type1 : POSSIBLE_CHANNEL_TYPES) {
+                    for (int type2 : POSSIBLE_CHANNEL_TYPES) {
+                        // only test upper triangle
+                        if (rate1 > rate2 || type1 > type2) {
+                            continue;
+                        }
+                        c.perform(() -> {
+                                runMultiChannelRateIndependencyTest(
+                                        sensorType, rate1, rate2, type1, type2);},
+                                String.format("rate1 %d, rate2 %d, type1 %d, type2 %d",
+                                              rate1, rate2, type1, type2));
+                    }
+                }
+            }
+        }
+        c.judge();
+    }
+
+    public void runMultiModeRateIndependencyTestGroup(int sensorType) {
+        TestResultCollector c = new TestResultCollector(
+                "testRateIndependency" + SensorCtsHelper.sensorTypeShortString(sensorType)
+                    + "MultiMode", TAG);
+
+        for (int rate : POSSIBLE_RATE_LEVELS) {
+            for (int type : POSSIBLE_CHANNEL_TYPES) {
+                for (int samplingPeriodUs : POSSIBLE_SAMPLE_PERIOD_US) {
+                    c.perform(() -> {runMultiModeRateIndependencyTest(
+                                        sensorType, rate, type, samplingPeriodUs);},
+                              String.format("rateLevel %d, memType %d, period %d",
+                                            rate, type, samplingPeriodUs));
+                }
+            }
+        }
+        c.judge();
+    }
+
+    private void runTimestampTestGroup(int sensorType) {
+        String stype = SensorCtsHelper.sensorTypeShortString(sensorType);
+
+        TestResultCollector c =
+                new TestResultCollector("testTimestamp" + stype, TAG);
+
+        for (int rateLevel : POSSIBLE_RATE_LEVELS) {
+            for (int memType : POSSIBLE_CHANNEL_TYPES) {
+                c.perform(
+                        () -> {
+                            runTimestampTest(sensorType, rateLevel, memType);
+                        },
+                        String.format("(%s, rate %d, memtype %d)", stype, rateLevel, memType));
+            }
+        }
+        c.judge();
+    }
+
     private void runSensorDirectReportTest(int sensorType, int memType, int rateLevel)
             throws AssertionError {
         Sensor s = mSensorManager.getDefaultSensor(sensorType);
@@ -262,24 +555,9 @@
                 || !s.isDirectChannelTypeSupported(memType)) {
             return;
         }
+        resetEvent();
 
-        try {
-            switch(memType) {
-                case SensorDirectChannel.TYPE_MEMORY_FILE:
-                    assertTrue("MemoryFile is null", mMemoryFile != null);
-                    mChannel = mSensorManager.createDirectChannel(mMemoryFile);
-                    break;
-                case SensorDirectChannel.TYPE_HARDWARE_BUFFER:
-                    assertTrue("HardwareBuffer is null", mHardwareBuffer != null);
-                    mChannel = mSensorManager.createDirectChannel(mHardwareBuffer);
-                    break;
-                default:
-                    Log.e(TAG, "Specified illegal memory type " + memType);
-                    return;
-            }
-        } catch (IllegalStateException e) {
-            mChannel = null;
-        }
+        mChannel = prepareDirectChannel(memType, false /* secondary */);
         assertTrue("createDirectChannel failed", mChannel != null);
 
         try {
@@ -300,6 +578,295 @@
         }
     }
 
+    private void runSingleChannelRateIndependencyTest(
+            int type1, int rateLevel1, int type2, int rateLevel2, int memType)
+                throws AssertionError {
+        Sensor s1 = mSensorManager.getDefaultSensor(type1);
+        Sensor s2 = mSensorManager.getDefaultSensor(type2);
+        if (s1 == null
+                || s1.getHighestDirectReportRateLevel() < rateLevel1
+                || !s1.isDirectChannelTypeSupported(memType)) {
+            return;
+        }
+
+        if (s2 == null
+                || s2.getHighestDirectReportRateLevel() < rateLevel2
+                || !s2.isDirectChannelTypeSupported(memType)) {
+            return;
+        }
+        resetEvent();
+
+        mChannel = prepareDirectChannel(memType, false /* secondary */);
+        assertTrue("createDirectChannel failed", mChannel != null);
+
+        try {
+            assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType));
+            waitBeforeStartSensor();
+
+            int token1 = mChannel.configure(s1, rateLevel1);
+            int token2 = mChannel.configure(s2, rateLevel2);
+            assertTrue("configure direct mChannel failed, token1 = " + token1, token1 > 0);
+            assertTrue("configure direct mChannel failed, token2 = " + token2, token2 > 0);
+
+            // run half amount of time so buffer is enough for both sensors
+            try {
+                SensorCtsHelper.sleep(TEST_RUN_TIME_PERIOD_MILLISEC / 2, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+
+            //stop sensor and analyze content
+            mChannel.configure(s1, SensorDirectChannel.RATE_STOP);
+            mChannel.configure(s2, SensorDirectChannel.RATE_STOP);
+
+            readSharedMemory(memType, false /*secondary*/);
+            checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC / 2, parseEntireBuffer(mBuffer, token1),
+                           type1, rateLevel1);
+            checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC / 2, parseEntireBuffer(mBuffer, token2),
+                           type2, rateLevel2);
+        } finally {
+            mChannel.close();
+            mChannel = null;
+        }
+    }
+
+    private void runMultiChannelRateIndependencyTest(
+            int type, int rateLevel1, int rateLevel2, int memType1, int memType2)
+                throws AssertionError {
+        Sensor s = mSensorManager.getDefaultSensor(type);
+        if (s == null
+                || s.getHighestDirectReportRateLevel() < Math.max(rateLevel1, rateLevel2)
+                || !s.isDirectChannelTypeSupported(memType1)
+                || !s.isDirectChannelTypeSupported(memType2)) {
+            return;
+        }
+        resetEvent();
+
+        mChannel = prepareDirectChannel(memType1, false /* secondary */);
+        mChannelSecondary = prepareDirectChannel(memType2, true /* secondary */);
+
+        try {
+            assertTrue("createDirectChannel failed", mChannel != null);
+            assertTrue("Shared memory is not formatted",
+                       isSharedMemoryFormatted(memType1));
+
+            assertTrue("createDirectChannel(secondary) failed", mChannelSecondary != null);
+            assertTrue("Shared memory(secondary) is not formatted",
+                       isSharedMemoryFormatted(memType2, true));
+
+            waitBeforeStartSensor();
+
+            int token1 = mChannel.configure(s, rateLevel1);
+            int token2 = mChannelSecondary.configure(s, rateLevel2);
+            assertTrue("configure direct mChannel failed", token1 > 0);
+            assertTrue("configure direct mChannelSecondary failed", token2 > 0);
+
+            waitSensorCollection();
+
+            //stop sensor and analyze content
+            mChannel.configure(s, SensorDirectChannel.RATE_STOP);
+            mChannelSecondary.configure(s, SensorDirectChannel.RATE_STOP);
+
+            // check rate
+            readSharedMemory(memType1, false /*secondary*/);
+            checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, parseEntireBuffer(mBuffer, token1),
+                           type, rateLevel1);
+
+            readSharedMemory(memType2, true /*secondary*/);
+            checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, parseEntireBuffer(mBuffer, token2),
+                           type, rateLevel2);
+        } finally {
+            if (mChannel != null) {
+                mChannel.close();
+                mChannel = null;
+            }
+            if (mChannelSecondary != null) {
+                mChannelSecondary.close();
+                mChannelSecondary = null;
+            }
+        }
+    }
+
+    private void runMultiModeRateIndependencyTest(
+            int type , int rateLevel, int memType, int samplingPeriodUs)
+                throws AssertionError {
+        final Sensor s = mSensorManager.getDefaultSensor(type);
+        if (s == null
+                || s.getHighestDirectReportRateLevel() < rateLevel
+                || !s.isDirectChannelTypeSupported(memType)) {
+            return;
+        }
+
+        if (samplingPeriodUs == 0) {
+            samplingPeriodUs = s.getMinDelay();
+        }
+
+        if (samplingPeriodUs < s.getMinDelay()) {
+            return;
+        }
+        resetEvent();
+
+        mChannel = prepareDirectChannel(memType, false /* secondary */);
+        assertTrue("createDirectChannel failed", mChannel != null);
+        SensorEventCollection listener = new SensorEventCollection(s);
+
+        try {
+            waitBeforeStartSensor();
+            int token = mChannel.configure(s, rateLevel);
+            boolean registerRet = mSensorManager.registerListener(listener, s, samplingPeriodUs);
+            assertTrue("Register listener failed", registerRet);
+
+            waitSensorCollection();
+
+            mChannel.configure(s, SensorDirectChannel.RATE_STOP);
+            mSensorManager.unregisterListener(listener);
+
+            // check direct report rate
+            readSharedMemory(memType, false /*secondary*/);
+            List<DirectReportSensorEvent> events = parseEntireBuffer(mBuffer, token);
+            checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, events, type, rateLevel);
+
+            // check callback interface rate
+            checkEventRateUs(TEST_RUN_TIME_PERIOD_MILLISEC, listener.getEvents(), type,
+                             samplingPeriodUs);
+        } finally {
+            mChannel.close();
+            mChannel = null;
+            mSensorManager.unregisterListener(listener);
+        }
+    }
+
+    private void runTimestampTest(int type, int rateLevel, int memType) {
+        Sensor s = mSensorManager.getDefaultSensor(type);
+        if (s == null
+                || s.getHighestDirectReportRateLevel() < rateLevel
+                || !s.isDirectChannelTypeSupported(memType)) {
+            return;
+        }
+        resetEvent();
+
+        mChannel = prepareDirectChannel(memType, false /* secondary */);
+        assertTrue("createDirectChannel failed", mChannel != null);
+
+        SensorEventCollection listener = new SensorEventCollection(s);
+
+        try {
+            float nominalFreq = getNominalFreq(rateLevel);
+            int samplingPeriodUs = Math.max((int) (1e6f / nominalFreq), s.getMinDelay());
+
+            assertTrue("Shared memory is not formatted",
+                       isSharedMemoryFormatted(memType));
+
+            int token = mChannel.configure(s, rateLevel);
+            assertTrue("configure direct mChannel failed", token > 0);
+
+            boolean registerRet = mSensorManager.registerListener(listener, s, samplingPeriodUs);
+            assertTrue("Register listener failed", registerRet);
+
+            List<DirectReportSensorEvent> events = collectSensorEventsRealtime(
+                    memType, false /*secondary*/, TEST_RUN_TIME_PERIOD_MILLISEC);
+            assertTrue("Realtime event collection failed", events != null);
+            assertTrue("Realtime event collection got no data", events.size() > 0);
+
+            //stop sensor and analyze content
+            mChannel.configure(s, SensorDirectChannel.RATE_STOP);
+            mSensorManager.unregisterListener(listener);
+
+            // check rate
+            checkTimestampRelative(events, listener.getEvents());
+            checkTimestampAbsolute(events);
+        } finally {
+            mChannel.close();
+            mChannel = null;
+        }
+    }
+
+    private void runAtomicCounterTest(int sensorType, int memType) throws AssertionError {
+        Sensor s = mSensorManager.getDefaultSensor(sensorType);
+        if (s == null
+                || s.getHighestDirectReportRateLevel() == SensorDirectChannel.RATE_STOP
+                || !s.isDirectChannelTypeSupported(memType)) {
+            return;
+        }
+        resetEvent();
+
+        mChannel = prepareDirectChannel(memType, false /* secondary */);
+        assertTrue("createDirectChannel failed", mChannel != null);
+
+        try {
+            assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType));
+            waitBeforeStartSensor();
+
+            //int token = mChannel.configure(s, SensorDirectChannel.RATE_FAST);
+            int token = mChannel.configure(s, s.getHighestDirectReportRateLevel());
+            assertTrue("configure direct mChannel failed", token > 0);
+
+            checkAtomicCounterUpdate(memType, 30 * 1000); // half min
+
+            //stop sensor and analyze content
+            mChannel.configure(s, SensorDirectChannel.RATE_STOP);
+        } finally {
+            mChannel.close();
+            mChannel = null;
+        }
+    }
+
+    private void runReconfigureTest(int type, int memType) {
+        Sensor s = mSensorManager.getDefaultSensor(type);
+        if (s == null
+                || s.getHighestDirectReportRateLevel() == SensorDirectChannel.RATE_STOP
+                || !s.isDirectChannelTypeSupported(memType)) {
+            return;
+        }
+        resetEvent();
+
+        mChannel = prepareDirectChannel(memType, false /* secondary */);
+        assertTrue("createDirectChannel failed", mChannel != null);
+
+        try {
+            assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType));
+            waitBeforeStartSensor();
+
+            int offset = 0;
+            long counter = 1;
+            List<Integer> rateLevels = new ArrayList<>();
+            List<DirectReportSensorEvent> events;
+
+            rateLevels.add(s.getHighestDirectReportRateLevel());
+            rateLevels.add(s.getHighestDirectReportRateLevel());
+            if (s.getHighestDirectReportRateLevel() != SensorDirectChannel.RATE_NORMAL) {
+                rateLevels.add(SensorDirectChannel.RATE_NORMAL);
+            }
+
+            for (int rateLevel : rateLevels) {
+                int token = mChannel.configure(s, rateLevel);
+                assertTrue("configure direct mChannel failed", token > 0);
+
+                events = collectSensorEventsRealtime(memType, false /*secondary*/,
+                                                     TEST_RUN_TIME_PERIOD_MILLISEC,
+                                                     offset, counter);
+                // stop sensor
+                mChannel.configure(s, SensorDirectChannel.RATE_STOP);
+                checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, events, type, rateLevel);
+
+                // collect all events after stop
+                events = collectSensorEventsRealtime(memType, false /*secondary*/,
+                                                     REST_PERIOD_BEFORE_TEST_MILLISEC,
+                                                     offset, counter);
+                if (events.size() > 0) {
+                    offset += (events.size() * SENSORS_EVENT_SIZE ) % SHARED_MEMORY_SIZE;
+                    counter = events.get(events.size() - 1).serial;
+                }
+            }
+
+            // finally stop the report
+            mChannel.configure(s, SensorDirectChannel.RATE_STOP);
+        } finally {
+            mChannel.close();
+            mChannel = null;
+        }
+    }
+
     private void waitBeforeStartSensor() {
         // wait for sensor system to come to a rest after previous test to avoid flakiness.
         try {
@@ -310,7 +877,7 @@
     }
 
     private void waitSensorCollection() {
-        // wait for sensor system to come to a rest after previous test to avoid flakiness.
+        // wait for sensor collection to finish
         try {
             SensorCtsHelper.sleep(TEST_RUN_TIME_PERIOD_MILLISEC, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
@@ -318,6 +885,147 @@
         }
     }
 
+    private List<DirectReportSensorEvent> collectSensorEventsRealtime(
+            int memType, boolean secondary, int timeoutMs) {
+        return collectSensorEventsRealtime(memType, secondary, timeoutMs,
+                                          0 /*initialOffset*/, 1l /*initialCounter*/);
+    }
+
+    private List<DirectReportSensorEvent> collectSensorEventsRealtime(
+            int memType, boolean secondary, int timeoutMs, int initialOffset, long initialCounter) {
+        List<DirectReportSensorEvent> events = new ArrayList<>();
+        long endTime = SystemClock.elapsedRealtime() + timeoutMs;
+
+        long atomicCounter = initialCounter;
+        int offset = initialOffset;
+
+        long timeA = SystemClock.elapsedRealtimeNanos();
+        boolean synced = false;
+        int filtered = 0;
+
+        while (SystemClock.elapsedRealtime() < endTime) {
+            if (!readSharedMemory(
+                    memType, secondary, offset + ATOMIC_COUNTER_OFFSET, ATOMIC_COUNTER_SIZE)) {
+                return null;
+            }
+
+            long timeB = SystemClock.elapsedRealtimeNanos();
+            if (timeB - timeA > 1_000_000L ) { // > 1ms
+                synced = false;
+            }
+            timeA = timeB;
+
+            if (readAtomicCounter(offset) == atomicCounter) {
+                // read entire event again and parse
+                if (!readSharedMemory(memType, secondary, offset, SENSORS_EVENT_SIZE)) {
+                    return null;
+                }
+                DirectReportSensorEvent e = mEventPool.get();
+                assertNotNull("cannot get event from reserve", e);
+                parseSensorEvent(offset, e);
+
+                atomicCounter += 1;
+                if (synced) {
+                    events.add(e);
+                } else {
+                    ++filtered;
+                }
+
+                offset += SENSORS_EVENT_SIZE;
+                if (offset + SENSORS_EVENT_SIZE > SHARED_MEMORY_SIZE) {
+                    offset = 0;
+                }
+            } else {
+                synced = true;
+            }
+        }
+        Log.d(TAG, "filtered " + filtered + " events, remain " + events.size() + " events");
+        return events;
+    }
+
+    private void checkAtomicCounterUpdate(int memType, int timeoutMs) {
+        List<DirectReportSensorEvent> events = new ArrayList<>();
+        long endTime = SystemClock.elapsedRealtime() + timeoutMs;
+
+        boolean lastValid = false;
+        long atomicCounter = 1;
+        int lastOffset = 0;
+        int offset = 0;
+
+        byte[] lastArray = new byte[SENSORS_EVENT_SIZE];
+        DirectReportSensorEvent e = getEvent();
+
+        while (SystemClock.elapsedRealtime() < endTime) {
+            if (!readSharedMemory(memType, false/*secondary*/, lastOffset, SENSORS_EVENT_SIZE)
+                    || !readSharedMemory(memType, false/*secondary*/,
+                                         offset + ATOMIC_COUNTER_OFFSET, ATOMIC_COUNTER_SIZE)) {
+                throw new IllegalStateException("cannot read shared memory, type " + memType);
+            }
+
+            if (lastValid) {
+                boolean failed = false;
+                int i;
+                for (i = 0; i < SENSORS_EVENT_SIZE; ++i) {
+                    if (lastArray[i] != mBuffer[lastOffset + i]) {
+                        failed = true;
+                        break;
+                    }
+                }
+
+                if (failed) {
+                    byte[] currentArray = new byte[SENSORS_EVENT_SIZE];
+                    System.arraycopy(mBuffer, lastOffset, currentArray, 0, SENSORS_EVENT_SIZE);
+
+                    // wait for 100ms and read again to see if the change settle
+                    try {
+                        SensorCtsHelper.sleep(100, TimeUnit.MILLISECONDS);
+                    } catch (InterruptedException ex) {
+                        Thread.currentThread().interrupt();
+                    }
+
+                    byte[] delayedRead = new byte[SENSORS_EVENT_SIZE];
+                    if (!readSharedMemory(
+                                memType, false/*secondary*/, lastOffset, SENSORS_EVENT_SIZE)) {
+                        throw new IllegalStateException(
+                                "cannot read shared memory, type " + memType);
+                    }
+                    System.arraycopy(mBuffer, lastOffset, delayedRead, 0, SENSORS_EVENT_SIZE);
+
+                    fail(String.format(
+                            "At offset %d(0x%x), byte %d(0x%x) changed after atomicCounter"
+                                + "(expecting %d, 0x%x) update, old = [%s], new = [%s], "
+                                + "delayed = [%s]",
+                            lastOffset, lastOffset, i, i, atomicCounter, atomicCounter,
+                            SensorCtsHelper.bytesToHex(lastArray, -1, -1),
+                            SensorCtsHelper.bytesToHex(currentArray, -1, -1),
+                            SensorCtsHelper.bytesToHex(delayedRead, -1, -1)));
+                }
+            }
+
+            if (readAtomicCounter(offset) == atomicCounter) {
+                // read entire event again and parse
+                if (!readSharedMemory(memType, false/*secondary*/, offset, SENSORS_EVENT_SIZE)) {
+                    throw new IllegalStateException("cannot read shared memory, type " + memType);
+                }
+                parseSensorEvent(offset, e);
+
+                atomicCounter += 1;
+
+                lastOffset = offset;
+                System.arraycopy(mBuffer, lastOffset, lastArray, 0, SENSORS_EVENT_SIZE);
+                lastValid = true;
+
+                offset += SENSORS_EVENT_SIZE;
+                if (offset + SENSORS_EVENT_SIZE > SHARED_MEMORY_SIZE) {
+                    offset = 0;
+                }
+            }
+        }
+        Log.d(TAG, "at finish checkAtomicCounterUpdate has atomic counter = " + atomicCounter);
+        // atomicCounter will not wrap back in reasonable amount of time
+        assertTrue("Realtime event collection got no data", atomicCounter != 1);
+    }
+
     private MemoryFile allocateMemoryFile() {
         MemoryFile memFile = null;
         try {
@@ -338,6 +1046,68 @@
         return hardwareBuffer;
     }
 
+    private SensorDirectChannel prepareDirectChannel(int memType, boolean secondary) {
+        SensorDirectChannel channel = null;
+
+        try {
+            switch(memType) {
+                case SensorDirectChannel.TYPE_MEMORY_FILE: {
+                    MemoryFile memoryFile = secondary ? mMemoryFileSecondary : mMemoryFile;
+                    assertTrue("MemoryFile" + (secondary ? "(secondary)" : "") + " is null",
+                               memoryFile != null);
+                    channel = mSensorManager.createDirectChannel(memoryFile);
+                    break;
+                }
+                case SensorDirectChannel.TYPE_HARDWARE_BUFFER: {
+                    HardwareBuffer hardwareBuffer
+                            = secondary ? mHardwareBufferSecondary : mHardwareBuffer;
+                    assertTrue("HardwareBuffer" + (secondary ? "(secondary)" : "") + " is null",
+                               hardwareBuffer != null);
+                    channel = mSensorManager.createDirectChannel(hardwareBuffer);
+                    break;
+                }
+                default:
+                    Log.e(TAG, "Specified illegal memory type " + memType);
+            }
+        } catch (IllegalStateException | UncheckedIOException e) {
+            Log.e(TAG, "Cannot initialize channel for memory type " + memType
+                    + ", details:" + e);
+            channel = null;
+        }
+        return channel;
+    }
+
+    private boolean readSharedMemory(int memType, boolean secondary, int offset, int length) {
+        switch(memType) {
+            case SensorDirectChannel.TYPE_MEMORY_FILE:
+                try {
+                    MemoryFile f = secondary ? mMemoryFileSecondary : mMemoryFile;
+                    if (f.readBytes(mBuffer, offset, offset, length) != length) {
+                        Log.e(TAG, "cannot read entire MemoryFile");
+                        return false;
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, "accessing MemoryFile causes IOException");
+                    return false;
+                }
+                return true;
+            case SensorDirectChannel.TYPE_HARDWARE_BUFFER:
+                return nativeReadHardwareBuffer(
+                        secondary ? mHardwareBufferSecondary : mHardwareBuffer,
+                        mBuffer, offset, offset, length);
+            default:
+                return false;
+        }
+    }
+
+    private boolean readSharedMemory(int memType, boolean secondary) {
+        return readSharedMemory(memType, secondary, 0, SHARED_MEMORY_SIZE);
+    }
+
+    private boolean readSharedMemory(int memType) {
+        return readSharedMemory(memType, false /*secondary*/);
+    }
+
     private boolean isMemoryTypeNeeded(int memType) {
         List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
         for (Sensor s : sensorList) {
@@ -349,17 +1119,11 @@
     }
 
     private boolean isSharedMemoryFormatted(int memType) {
-        if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
-            if (!readMemoryFileContent()) {
-                Log.e(TAG, "Read MemoryFile content fail");
-                return false;
-            }
-        } else {
-            if (!readHardwareBufferContent()) {
-                Log.e(TAG, "Read HardwareBuffer content fail");
-                return false;
-            }
-        }
+        return isSharedMemoryFormatted(memType, false /* secondary */);
+    }
+
+    private boolean isSharedMemoryFormatted(int memType, boolean secondary) {
+        readSharedMemory(memType, secondary);
 
         for (byte b : mBuffer) {
             if (b != 0) {
@@ -370,17 +1134,13 @@
     }
 
     private void checkSharedMemoryContent(Sensor s, int memType, int rateLevel, int token) {
-        if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
-            assertTrue("read MemoryFile content failed", readMemoryFileContent());
-        } else {
-            assertTrue("read HardwareBuffer content failed", readHardwareBufferContent());
-        }
+        assertTrue("read mem type " + memType + " content failed", readSharedMemory(memType));
 
         int offset = 0;
         int nextSerial = 1;
-        DirectReportSensorEvent e = new DirectReportSensorEvent();
+        DirectReportSensorEvent e = getEvent();
         while (offset <= SHARED_MEMORY_SIZE - SENSORS_EVENT_SIZE) {
-            parseSensorEvent(mBuffer, offset, e);
+            parseSensorEvent(offset, e);
 
             if (e.serial == 0) {
                 // reaches end of events
@@ -440,7 +1200,7 @@
             maxEvents = (int) Math.ceil(
                     nominalFreq
                     * FREQ_UPPER_BOUND
-                    * (TEST_RUN_TIME_PERIOD_MILLISEC - ALLOWED_SENSOR_INIT_TIME_MILLISEC)
+                    * TEST_RUN_TIME_PERIOD_MILLISEC
                     * (1 + MERCY_FACTOR)
                     / 1000);
 
@@ -449,47 +1209,443 @@
         }
     }
 
-    private boolean readMemoryFileContent() {
-        try {
-            if (mMemoryFile.readBytes(mBuffer, 0, 0, SHARED_MEMORY_SIZE)
-                    != SHARED_MEMORY_SIZE) {
-                Log.e(TAG, "cannot read entire MemoryFile");
-                return false;
-            }
-        } catch (IOException e) {
-            Log.e(TAG, "accessing MemoryFile cause IOException");
-            return false;
+    private void checkEventRate(int testTimeMs, List<DirectReportSensorEvent> events,
+                                int type, int rateLevel) {
+        assertTrue("insufficient events of type " + type, events.size() > 1);
+        for (DirectReportSensorEvent e : events) {
+            assertTrue("incorrect type " + e.type + " expecting " + type, e.type == type);
         }
-        return true;
+
+        // check number of events
+        int[] minMax = calculateExpectedNEvents(testTimeMs, rateLevel);
+        assertTrue(
+                "Number of event of type " + type + " is " + events.size()
+                    + ", which is not in range [" + minMax[0] + ", " + minMax[1] + "].",
+                minMax[0] <= events.size() && events.size() <= minMax[1]);
+
+        // intervals
+        List<Long> intervals = new ArrayList<>(events.size() - 1);
+        long minInterval = Long.MAX_VALUE;
+        long maxInterval = Long.MIN_VALUE;
+        long averageInterval = 0;
+        for (int i = 1; i < events.size(); ++i) {
+            long d = events.get(i).ts - events.get(i-1).ts;
+            averageInterval += d;
+            minInterval = Math.min(d, minInterval);
+            maxInterval = Math.max(d, maxInterval);
+            intervals.add(d);
+        }
+        averageInterval /= (events.size() - 1);
+
+        // average rate
+        float averageFreq = 1e9f / averageInterval;
+        float nominalFreq = getNominalFreq(rateLevel);
+        Log.d(TAG, String.format(
+                "checkEventRate type %d: averageFreq %f, nominalFreq %f, lbound %f, ubound %f",
+                type, averageFreq, nominalFreq,
+                nominalFreq * FREQ_LOWER_BOUND,
+                nominalFreq * FREQ_UPPER_BOUND));
+        assertTrue("Average frequency of type " + type + " rateLevel " + rateLevel
+                        + " is " + averageFreq,
+                   nominalFreq * FREQ_LOWER_BOUND * (1 - MERCY_FACTOR) <= averageFreq &&
+                       averageFreq <= nominalFreq * FREQ_UPPER_BOUND * (1 + MERCY_FACTOR));
+
+        // jitter variance
+        List<Long> percentileValues =
+                SensorCtsHelper.getPercentileValue(intervals, 0.025f, (1 - 0.025f));
+        assertTrue("Timestamp jitter of type " + type + " rateLevel " + rateLevel + " is "
+                        + (percentileValues.get(1) - percentileValues.get(0) / 1000) + " us, "
+                        + "while average interval is " + (averageInterval / 1000) + "us, over-range",
+                   (percentileValues.get(1) - percentileValues.get(0)) / averageInterval < 0.05);
+        Log.d(TAG, String.format(
+                "checkEventRate type %d, timestamp interval range %f - %f ms, " +
+                    "span %f ms, %.2f%% of averageInterval",
+                    type, percentileValues.get(0)/1e6f, percentileValues.get(1)/1e6f,
+                    (percentileValues.get(1) - percentileValues.get(0))/1e6f,
+                    (percentileValues.get(1) - percentileValues.get(0)) / averageInterval * 100.f));
+
     }
 
-    private boolean readHardwareBufferContent() {
-        return nativeReadHardwareBuffer(mHardwareBuffer, mBuffer, 0, 0, SHARED_MEMORY_SIZE);
+    private void checkEventRateUs(int testTimeMs, List<DirectReportSensorEvent> events,
+                                  int type, int samplingPeriodUs) {
+        // samplingPeriodUs must be a valid one advertised by sensor
+        assertTrue("insufficient events of type " + type, events.size() > 1);
+        for (DirectReportSensorEvent e : events) {
+            assertTrue("incorrect type " + e.type + " expecting " + type, e.type == type);
+        }
+
+        // check number of events
+        int[] minMax = calculateExpectedNEventsUs(testTimeMs, samplingPeriodUs);
+        assertTrue(
+                "Number of event of type " + type + " is " + events.size()
+                    + ", which is not in range [" + minMax[0] + ", " + minMax[1] + "].",
+                minMax[0] <= events.size() && events.size() <= minMax[1]);
+
+        // intervals
+        List<Long> intervals = new ArrayList<>(events.size() - 1);
+        long minInterval = Long.MAX_VALUE;
+        long maxInterval = Long.MIN_VALUE;
+        long averageInterval = 0;
+        for (int i = 1; i < events.size(); ++i) {
+            long d = events.get(i).ts - events.get(i-1).ts;
+            averageInterval += d;
+            minInterval = Math.min(d, minInterval);
+            maxInterval = Math.max(d, maxInterval);
+            intervals.add(d);
+        }
+        averageInterval /= (events.size() - 1);
+
+        // average rate
+        float averageFreq = 1e9f / averageInterval;
+        float nominalFreq = 1e6f / samplingPeriodUs;
+        Log.d(TAG, String.format(
+                "checkEventRateUs type %d: averageFreq %f, nominalFreq %f, lbound %f, ubound %f",
+                type, averageFreq, nominalFreq,
+                nominalFreq * FREQ_LOWER_BOUND_POLL,
+                nominalFreq * FREQ_UPPER_BOUND_POLL));
+        assertTrue("Average frequency of type " + type
+                        + " is " + averageFreq,
+                   nominalFreq * FREQ_LOWER_BOUND_POLL * (1 - MERCY_FACTOR) <= averageFreq &&
+                       averageFreq <= nominalFreq * FREQ_UPPER_BOUND_POLL * (1 + MERCY_FACTOR));
+
+        // jitter variance
+        List<Long> percentileValues =
+                SensorCtsHelper.getPercentileValue(intervals, 0.025f, (1 - 0.025f));
+        assertTrue("Timestamp jitter of type " + type + " is "
+                        + (percentileValues.get(1) - percentileValues.get(0) / 1000) + " us, "
+                        + "while average interval is " + (averageInterval / 1000) + "us, over-range",
+                   (percentileValues.get(1) - percentileValues.get(0)) / averageInterval < 0.05);
+        Log.d(TAG, String.format(
+                "checkEventRateUs type %d, timestamp interval range %f - %f ms, " +
+                    "span %f ms, %.2f%% of averageInterval",
+                    type, percentileValues.get(0)/1e6f, percentileValues.get(1)/1e6f,
+                    (percentileValues.get(1) - percentileValues.get(0)) / 1e6f,
+                    (percentileValues.get(1) - percentileValues.get(0)) / averageInterval * 100.f));
     }
 
-    private class DirectReportSensorEvent {
-        int size;
-        int token;
-        int type;
-        int serial;
-        long ts;
-        float x;
-        float y;
-        float z;
+    private void allocateSharedMemory() {
+        if (mNeedMemoryFile) {
+            mMemoryFile = allocateMemoryFile();
+            mMemoryFileSecondary = allocateMemoryFile();
+        }
+
+        if (mNeedHardwareBuffer) {
+            mHardwareBuffer = allocateHardwareBuffer();
+            mHardwareBufferSecondary = allocateHardwareBuffer();
+        }
+    }
+
+    private void freeSharedMemory() {
+        if (mMemoryFile != null) {
+            mMemoryFile.close();
+            mMemoryFile = null;
+        }
+
+        if (mMemoryFileSecondary != null) {
+            mMemoryFileSecondary.close();
+            mMemoryFileSecondary = null;
+        }
+
+        if (mHardwareBuffer != null) {
+            mHardwareBuffer.close();
+            mHardwareBuffer = null;
+        }
+
+        if (mHardwareBufferSecondary != null) {
+            mHardwareBufferSecondary.close();
+            mHardwareBufferSecondary = null;
+        }
+    }
+
+    private float getNominalFreq(int rateLevel) {
+        float nominalFreq = 0;
+        switch (rateLevel) {
+            case SensorDirectChannel.RATE_NORMAL:
+                nominalFreq = RATE_NORMAL_NOMINAL;
+                break;
+            case SensorDirectChannel.RATE_FAST:
+                nominalFreq = RATE_FAST_NOMINAL;
+                break;
+            case SensorDirectChannel.RATE_VERY_FAST:
+                nominalFreq = RATE_VERY_FAST_NOMINAL;
+                break;
+        }
+        return nominalFreq;
+    }
+
+    private int[] calculateExpectedNEvents(int timeMs, int rateLevel) {
+        int[] minMax = new int[] { -1, Integer.MAX_VALUE };
+        float nominalFreq = getNominalFreq(rateLevel);
+        if (nominalFreq != 0) {
+            // min
+            if (timeMs > ALLOWED_SENSOR_INIT_TIME_MILLISEC) {
+                minMax[0] = (int) Math.floor(
+                        nominalFreq
+                        * FREQ_LOWER_BOUND
+                        * (timeMs - ALLOWED_SENSOR_INIT_TIME_MILLISEC)
+                        * (1 - MERCY_FACTOR)
+                        / 1000);
+            }
+            // max
+            minMax[1] = (int) Math.ceil(
+                    nominalFreq
+                    * FREQ_UPPER_BOUND
+                    * timeMs
+                    * (1 + MERCY_FACTOR)
+                    / 1000);
+        }
+        return minMax;
+    }
+
+    private void checkTimestampAbsolute(List<DirectReportSensorEvent> events) {
+        final int MAX_DETAIL_ITEM = 10;
+
+        StringBuffer buf = new StringBuffer();
+        int oneMsEarlyCount = 0;
+        int fiveMsLateCount = 0;
+        int tenMsLateCount = 0;
+        int errorCount = 0;
+
+        for (int i = 0; i < events.size(); ++i) {
+            DirectReportSensorEvent e = events.get(i);
+            long d = e.arrivalTs - e.ts;
+            boolean oneMsEarly = d < -1000_000;
+            boolean fiveMsLate = d > 5000_000;
+            boolean tenMsLate = d > 10_000_000;
+
+            if (oneMsEarly || fiveMsLate || tenMsLate) {
+                oneMsEarlyCount += oneMsEarly ? 1 : 0;
+                fiveMsLateCount += fiveMsLate ? 1 : 0;
+                tenMsLateCount += tenMsLate ? 1 : 0;
+
+                if (errorCount++ < MAX_DETAIL_ITEM) {
+                    buf.append("[").append(i).append("] diff = ").append(d / 1e6f).append(" ms; ");
+                }
+            }
+        }
+
+        Log.d(TAG, String.format("Irregular timestamp, %d, %d, %d out of %d",
+                    oneMsEarlyCount, fiveMsLateCount, tenMsLateCount, events.size()));
+
+        if (CHECK_ABSOLUTE_LATENCY) {
+            assertTrue(String.format(
+                    "Timestamp error, out of %d events, %d is >1ms early, %d is >5ms late, "
+                        + "%d is >10ms late, details: %s%s",
+                        events.size(), oneMsEarlyCount, fiveMsLateCount, tenMsLateCount,
+                        buf.toString(), errorCount > MAX_DETAIL_ITEM ? "..." : ""),
+                    oneMsEarlyCount == 0
+                        && fiveMsLateCount <= events.size() / 20
+                        && tenMsLateCount <= events.size() / 100);
+        }
+    }
+
+    private void checkTimestampRelative(List<DirectReportSensorEvent> directEvents,
+                                        List<DirectReportSensorEvent> pollEvents) {
+        if (directEvents.size() < 10 || pollEvents.size() < 10) {
+            // cannot check with so few data points
+            return;
+        }
+
+        long directAverageLatency = 0;
+        for (DirectReportSensorEvent e : directEvents) {
+            directAverageLatency += e.arrivalTs - e.ts;
+        }
+        directAverageLatency /= directEvents.size();
+
+        long pollAverageLatency = 0;
+        for (DirectReportSensorEvent e : pollEvents) {
+            pollAverageLatency += e.arrivalTs - e.ts;
+        }
+        pollAverageLatency /= pollEvents.size();
+
+        Log.d(TAG, String.format("Direct, poll latency = %f, %f ms",
+                directAverageLatency / 1e6f, pollAverageLatency / 1e6f));
+        assertTrue(
+                String.format("Direct, poll latency = %f, %f ms, expect direct < poll",
+                    directAverageLatency / 1e6f,
+                    pollAverageLatency / 1e6f),
+                directAverageLatency < pollAverageLatency + 1000_000);
+    }
+
+    private int[] calculateExpectedNEventsUs(int timeMs, int samplingPeriodUs) {
+        int[] minMax = new int[2];
+        minMax[0] = Math.max((int) Math.floor(
+                (timeMs - ALLOWED_SENSOR_INIT_TIME_MILLISEC) * 1000/ samplingPeriodUs), 0);
+        minMax[1] = (int) Math.ceil(timeMs * 1000 * 2 / samplingPeriodUs);
+        return minMax;
+    }
+
+    private static class DirectReportSensorEvent {
+        public int size;
+        public int token;
+        public int type;
+        public long serial;
+        public long ts;
+        public float x;
+        public float y;
+        public float z;
+        public long arrivalTs;
     };
 
+    // EventPool to avoid allocating too many event objects and hitting GC during test
+    private static class EventPool {
+        public EventPool(int n) {
+            mEvents = Arrays.asList(new DirectReportSensorEvent[n]);
+            for (int i = 0; i < n; ++i) {
+                mEvents.set(i, new DirectReportSensorEvent());
+            }
+            reset();
+        }
+
+        public synchronized void reset() {
+            Log.d(TAG, "Reset EventPool (" + mIndex + " events used)");
+            mIndex = 0;
+        }
+
+        public synchronized DirectReportSensorEvent get() {
+            if (mIndex < mEvents.size()) {
+                return mEvents.get(mIndex++);
+            } else {
+                throw new IllegalStateException("EventPool depleted");
+            }
+        }
+
+        private List<DirectReportSensorEvent> mEvents;
+        private int mIndex;
+    };
+
+    private DirectReportSensorEvent getEvent() {
+        return mEventPool.get();
+    }
+
+    private DirectReportSensorEvent getEvent(DirectReportSensorEvent e) {
+        DirectReportSensorEvent event = mEventPool.get();
+        event.size = e.size;
+        event.token = e.token;
+        event.type = e.type;
+        event.serial = e.serial;
+        event.ts = e.ts;
+        event.x = e.x;
+        event.y = e.y;
+        event.z = e.z;
+        event.arrivalTs = e.arrivalTs;
+        return event;
+    }
+
+    private void resetEvent() {
+        mEventPool.reset();
+    }
+
+    private class SensorEventCollection implements SensorEventListener {
+        List<DirectReportSensorEvent> mEvents = new ArrayList<>();
+        Sensor mSensor;
+
+        public SensorEventCollection(Sensor s) {
+            mSensor = s;
+        }
+
+        List<DirectReportSensorEvent> getEvents() {
+            return mEvents;
+        }
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            if (mSensor == null || event.sensor == mSensor) {
+                DirectReportSensorEvent e = mEventPool.get();
+                e.size = SENSORS_EVENT_SIZE;
+                e.token = event.sensor.getType();
+                e.type = e.token;
+                e.serial = -1;
+                e.ts = event.timestamp;
+                e.arrivalTs = SystemClock.elapsedRealtimeNanos();
+
+                e.x = event.values[0];
+                if (event.values.length > 1) {
+                    e.y = event.values[1];
+                }
+                if (event.values.length > 2) {
+                    e.z = event.values[2];
+                }
+                mEvents.add(e);
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor s, int accuracy) {
+            // do nothing
+        }
+    };
+
+    private List<DirectReportSensorEvent> parseEntireBuffer(byte[] buffer, int token) {
+        int offset = 0;
+        int nextSerial = 1;
+        List<DirectReportSensorEvent> events = new ArrayList<>();
+
+        while (offset <= SHARED_MEMORY_SIZE - SENSORS_EVENT_SIZE) {
+            DirectReportSensorEvent e = getEvent();
+            parseSensorEvent(offset, e);
+
+            if (e.serial == 0) {
+                // reaches end of events
+                break;
+            }
+
+            assertTrue("incorrect size " + e.size + "  at offset " + offset,
+                    e.size == SENSORS_EVENT_SIZE);
+            assertTrue("incorrect serial " + e.serial + " at offset " + offset,
+                    e.serial == nextSerial);
+
+            if (e.token == token) {
+                events.add(e);
+            }
+
+            ++nextSerial;
+            offset += SENSORS_EVENT_SIZE;
+        }
+
+        return events;
+    }
+
+    // parse sensors_event_t from mBuffer and fill information into DirectReportSensorEvent
+    private void parseSensorEvent(int offset, DirectReportSensorEvent ev) {
+        mByteBuffer.position(offset);
+
+        ev.size = mByteBuffer.getInt();
+        ev.token = mByteBuffer.getInt();
+        ev.type = mByteBuffer.getInt();
+        ev.serial = ((long) mByteBuffer.getInt()) & 0xFFFFFFFFl; // signed=>unsigned
+        ev.ts = mByteBuffer.getLong();
+        ev.arrivalTs = SystemClock.elapsedRealtimeNanos();
+        ev.x = mByteBuffer.getFloat();
+        ev.y = mByteBuffer.getFloat();
+        ev.z = mByteBuffer.getFloat();
+    }
+
     // parse sensors_event_t and fill information into DirectReportSensorEvent
     private static void parseSensorEvent(byte [] buf, int offset, DirectReportSensorEvent ev) {
         ByteBuffer b = ByteBuffer.wrap(buf, offset, SENSORS_EVENT_SIZE);
-        b.order(ByteOrder.nativeOrder());
+        b.order(NATIVE_BYTE_ORDER);
 
         ev.size = b.getInt();
         ev.token = b.getInt();
         ev.type = b.getInt();
-        ev.serial = b.getInt();
+        ev.serial = ((long) b.getInt()) & 0xFFFFFFFFl; // signed=>unsigned
         ev.ts = b.getLong();
+        ev.arrivalTs = SystemClock.elapsedRealtimeNanos();
         ev.x = b.getFloat();
         ev.y = b.getFloat();
         ev.z = b.getFloat();
     }
+
+    private long readAtomicCounter(int offset) {
+        mByteBuffer.position(offset + ATOMIC_COUNTER_OFFSET);
+        return ((long) mByteBuffer.getInt()) & 0xFFFFFFFFl; // signed => unsigned
+    }
+
+    private static long readAtomicCounter(byte [] buf, int offset) {
+        ByteBuffer b = ByteBuffer.wrap(buf, offset + ATOMIC_COUNTER_OFFSET, ATOMIC_COUNTER_SIZE);
+        b.order(ByteOrder.nativeOrder());
+
+        return ((long) b.getInt()) & 0xFFFFFFFFl; // signed => unsigned
+    }
 }
diff --git a/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java
index 06aa815..bbe2006 100644
--- a/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -16,6 +16,7 @@
 package android.hardware.cts.helpers;
 
 import android.hardware.Sensor;
+import android.util.Log;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -325,4 +326,96 @@
         };
         return "";
     }
+
+    public static String sensorTypeShortString(int type) {
+        switch (type) {
+            case Sensor.TYPE_ACCELEROMETER:
+                return "Accel";
+            case Sensor.TYPE_GYROSCOPE:
+                return "Gyro";
+            case Sensor.TYPE_MAGNETIC_FIELD:
+                return "Mag";
+            case Sensor.TYPE_ACCELEROMETER_UNCALIBRATED:
+                return "UncalAccel";
+            case Sensor.TYPE_GYROSCOPE_UNCALIBRATED:
+                return "UncalGyro";
+            case Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+                return "UncalMag";
+            default:
+                return "Type_" + type;
+        }
+    }
+
+    public static class TestResultCollector {
+        private List<AssertionError> mErrorList = new ArrayList<>();
+        private List<String> mErrorStringList = new ArrayList<>();
+        private String mTestName;
+        private String mTag;
+
+        public TestResultCollector() {
+            this("Test");
+        }
+
+        public TestResultCollector(String test) {
+            this(test, "SensorCtsTest");
+        }
+
+        public TestResultCollector(String test, String tag) {
+            mTestName = test;
+            mTag = tag;
+        }
+
+        public void perform(Runnable r) {
+            perform(r, "");
+        }
+
+        public void perform(Runnable r, String s) {
+            try {
+                Log.d(mTag, mTestName + " running " + (s.isEmpty() ? "..." : s));
+                r.run();
+            } catch (AssertionError e) {
+                mErrorList.add(e);
+                mErrorStringList.add(s);
+                Log.e(mTag, mTestName + " error: " + e.getMessage());
+            }
+        }
+
+        public void judge() throws AssertionError {
+            if (mErrorList.isEmpty() && mErrorStringList.isEmpty()) {
+                return;
+            }
+
+            if (mErrorList.size() != mErrorStringList.size()) {
+                throw new IllegalStateException("Mismatch error and error message");
+            }
+
+            StringBuffer buf = new StringBuffer();
+            for (int i = 0; i < mErrorList.size(); ++i) {
+                buf.append("Test (").append(mErrorStringList.get(i)).append(") - Error: ")
+                    .append(mErrorList.get(i).getMessage()).append("; ");
+            }
+            throw new AssertionError(buf.toString());
+        }
+    }
+
+    public static String bytesToHex(byte[] bytes, int offset, int length) {
+        if (offset == -1) {
+            offset = 0;
+        }
+
+        if (length == -1) {
+            length = bytes.length;
+        }
+
+        final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+        char[] hexChars = new char[length * 3];
+        int v;
+        for (int i = 0; i < length; i++) {
+            v = bytes[offset + i] & 0xFF;
+            hexChars[i * 3] = hexArray[v >>> 4];
+            hexChars[i * 3 + 1] = hexArray[v & 0x0F];
+            hexChars[i * 3 + 2] = ' ';
+        }
+        return new String(hexChars);
+    }
 }
diff --git a/tests/signature/Android.mk b/tests/signature/Android.mk
index b78fb95..fec47b6 100644
--- a/tests/signature/Android.mk
+++ b/tests/signature/Android.mk
@@ -13,6 +13,10 @@
 # limitations under the License.
 
 LOCAL_PATH:= $(call my-dir)
+
+# cts-signature-common java library
+# =================================
+
 include $(CLEAR_VARS)
 
 # don't include this package in any target
@@ -20,19 +24,11 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsSignatureTestCases
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_MODULE := cts-signature-common
 
 LOCAL_SDK_VERSION := current
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner \
-    compatibility-device-util \
-    android-support-test \
-    legacy-android-test
-
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # signature-hostside java library (for testing)
 # ============================================================
@@ -40,7 +36,7 @@
 include $(CLEAR_VARS)
 
 # These files are for device-side only, so filter-out for host library
-LOCAL_DEVICE_ONLY_SOURCES := %/SignatureTest.java %/IntentTest.java %/CurrentApi.java
+LOCAL_DEVICE_ONLY_SOURCES := %/CurrentApi.java %/ApiDocumentParser.java
 
 LOCAL_SRC_FILES := $(filter-out $(LOCAL_DEVICE_ONLY_SOURCES), $(call all-java-files-under, src))
 
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/tests/signature/api-check/Android.mk
similarity index 60%
copy from hostsidetests/devicepolicy/app/VpnApp/Android.mk
copy to tests/signature/api-check/Android.mk
index 9723b97..013cc4d 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/tests/signature/api-check/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -12,23 +12,27 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
+
+# cts-api-signature-test java library
+# ===================================
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsVpnFirewallApp
-
+# don't include this package in any target
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_MODULE := cts-api-signature-test
 
 LOCAL_SDK_VERSION := current
 
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    cts-signature-common \
+    repackaged-legacy-test \
+    repackaged.android.test.runner \
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/tests/signature/api-check/android-test-mock-current-api/Android.mk
similarity index 65%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to tests/signature/api-check/android-test-mock-current-api/Android.mk
index 151379b..b60f6a3 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/tests/signature/api-check/android-test-mock-current-api/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -16,11 +16,9 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_PACKAGE_NAME := CtsAndroidTestMockCurrentApiSignatureTestCases
 
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_SIGNATURE_API_FILES := \
+    android-test-mock-current.api \
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
similarity index 70%
copy from tests/signature/AndroidManifest.xml
copy to tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
index 41a4233..5c88521 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2008 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.
@@ -16,16 +16,16 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts">
+          package="android.signature.cts.api.android_test_mock_current">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
     <application>
-        <uses-library android:name="android.test.runner"/>
+        <uses-library android:name="android.test.mock"/>
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature.cts"
-                     android:label="API Signature Test"/>
+    <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.signature.cts.api.android_test_mock_current"
+                     android:label="Android Test Mock Current API Signature Test"/>
 
 </manifest>
diff --git a/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
new file mode 100644
index 0000000..16b29a8
--- /dev/null
+++ b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?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 Android Test Mock Current API Signature test cases">
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <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="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAndroidTestMockCurrentApiSignatureTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.signature.cts.api.android_test_mock_current" />
+        <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+        <option name="instrumentation-arg" key="expected-api-files" value="android-test-mock-current.api" />
+        <option name="runtime-hint" value="5s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/tests/signature/api-check/android-test-runner-current-api/Android.mk
similarity index 65%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to tests/signature/api-check/android-test-runner-current-api/Android.mk
index 151379b..d840506 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/tests/signature/api-check/android-test-runner-current-api/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -16,11 +16,10 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_PACKAGE_NAME := CtsAndroidTestRunnerCurrentApiSignatureTestCases
 
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_SIGNATURE_API_FILES := \
+    android-test-mock-current.api \
+    android-test-runner-current.api \
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
similarity index 74%
copy from tests/signature/AndroidManifest.xml
copy to tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
index 41a4233..61de501 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2008 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.
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts">
+          package="android.signature.cts.api.android_test_runner_current">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
@@ -24,8 +24,8 @@
         <uses-library android:name="android.test.runner"/>
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature.cts"
-                     android:label="API Signature Test"/>
+    <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.signature.cts.api.android_test_runner_current"
+                     android:label="Android Test Runner Current API Signature Test"/>
 
 </manifest>
diff --git a/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
new file mode 100644
index 0000000..ecf7055
--- /dev/null
+++ b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
@@ -0,0 +1,38 @@
+<?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 Android Test Runner Current API Signature test cases">
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <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="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="android-test-runner-current.api->/data/local/tmp/signature-test/android-test-runner-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAndroidTestRunnerCurrentApiSignatureTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.signature.cts.api.android_test_runner_current" />
+        <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+        <option name="instrumentation-arg" key="expected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
+        <option name="runtime-hint" value="5s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
similarity index 65%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to tests/signature/api-check/apache-http-legacy-current-api/Android.mk
index 151379b..df69004 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -16,11 +16,9 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_PACKAGE_NAME := CtsApacheHttpLegacyCurrentApiSignatureTestCases
 
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_SIGNATURE_API_FILES := \
+    apache-http-legacy-current.api \
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
similarity index 71%
copy from tests/signature/AndroidManifest.xml
copy to tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
index 41a4233..eaf118b 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2008 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.
@@ -16,16 +16,14 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts">
+          package="android.signature.cts.api.apache_http_legacy_current">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
-    <application>
-        <uses-library android:name="android.test.runner"/>
-    </application>
+    <application/>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature.cts"
-                     android:label="API Signature Test"/>
+    <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.signature.cts.api.apache_http_legacy_current"
+                     android:label="Apache Http Legacy Current API Signature Test"/>
 
 </manifest>
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
new file mode 100644
index 0000000..a5e69a9
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?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 Apache Http Legacy Current API Signature test cases">
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <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" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsApacheHttpLegacyCurrentApiSignatureTestCases.apk" />
+    </target_preparer>
+    <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="runtime-hint" value="5s" />
+    </test>
+</configuration>
diff --git a/tests/signature/api-check/build_signature_apk.mk b/tests/signature/api-check/build_signature_apk.mk
new file mode 100644
index 0000000..f05d1a6
--- /dev/null
+++ b/tests/signature/api-check/build_signature_apk.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.
+
+# Specify the following variables before including:
+#
+#     LOCAL_PACKAGE_NAME
+#         the name of the package
+#
+#     LOCAL_SIGNATURE_API_FILES
+#         the list of api files needed
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
+
+LOCAL_ADDITIONAL_DEPENDENCIES += \
+    $(addprefix $(COMPATIBILITY_TESTCASES_OUT_cts)/,$(LOCAL_SIGNATURE_API_FILES))
+
+include $(BUILD_CTS_PACKAGE)
+
+LOCAL_SIGNATURE_API_FILES :=
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/tests/signature/api-check/current-api/Android.mk
similarity index 65%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to tests/signature/api-check/current-api/Android.mk
index 151379b..0e7997d 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/tests/signature/api-check/current-api/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -16,11 +16,11 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_PACKAGE_NAME := CtsCurrentApiSignatureTestCases
 
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_SIGNATURE_API_FILES := \
+    current.api \
+    android-test-mock-current.api \
+    android-test-runner-current.api \
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/api-check/current-api/AndroidManifest.xml
similarity index 72%
copy from tests/signature/AndroidManifest.xml
copy to tests/signature/api-check/current-api/AndroidManifest.xml
index 41a4233..7dc5730 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/api-check/current-api/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2008 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.
@@ -16,16 +16,14 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts">
+          package="android.signature.cts.api.current">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
-    <application>
-        <uses-library android:name="android.test.runner"/>
-    </application>
+    <application/>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature.cts"
-                     android:label="API Signature Test"/>
+    <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.signature.cts.api.current"
+                     android:label="Current API Signature Test"/>
 
 </manifest>
diff --git a/tests/signature/api-check/current-api/AndroidTest.xml b/tests/signature/api-check/current-api/AndroidTest.xml
new file mode 100644
index 0000000..9345bba
--- /dev/null
+++ b/tests/signature/api-check/current-api/AndroidTest.xml
@@ -0,0 +1,42 @@
+<?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 Current API Signature test cases">
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <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="current.api->/data/local/tmp/signature-test/current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="android-test-runner-current.api->/data/local/tmp/signature-test/android-test-runner-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsCurrentApiSignatureTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.signature.cts.api.current" />
+        <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+        <option name="instrumentation-arg" key="expected-api-files" value="current.api" />
+        <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
+        <option name="runtime-hint" value="30s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/tests/signature/api-check/legacy-test-26-api/Android.mk
similarity index 65%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to tests/signature/api-check/legacy-test-26-api/Android.mk
index 151379b..699bd0c 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/tests/signature/api-check/legacy-test-26-api/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -16,11 +16,9 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_PACKAGE_NAME := CtsLegacyTest26ApiSignatureTestCases
 
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_SIGNATURE_API_FILES := \
+    legacy-test-current.api \
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/api-check/legacy-test-26-api/AndroidManifest.xml
similarity index 69%
copy from tests/signature/AndroidManifest.xml
copy to tests/signature/api-check/legacy-test-26-api/AndroidManifest.xml
index 41a4233..636dfd3 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/api-check/legacy-test-26-api/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2008 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.
@@ -16,16 +16,16 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts">
+          package="android.signature.cts.api.legacy_test_26">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
-    <application>
-        <uses-library android:name="android.test.runner"/>
-    </application>
+    <uses-sdk android:minSdkVersion="25" android:targetSdkVersion="26"/>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature.cts"
-                     android:label="API Signature Test"/>
+    <application/>
+
+    <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.signature.cts.api.legacy_test_26"
+                     android:label="Legacy Test 26 API Signature Test"/>
 
 </manifest>
diff --git a/tests/signature/api-check/legacy-test-26-api/AndroidTest.xml b/tests/signature/api-check/legacy-test-26-api/AndroidTest.xml
new file mode 100644
index 0000000..ecb3299
--- /dev/null
+++ b/tests/signature/api-check/legacy-test-26-api/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?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 Legacy Test 26 API Signature test cases">
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <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="legacy-test-current.api->/data/local/tmp/signature-test/legacy-test-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLegacyTest26ApiSignatureTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.signature.cts.api.legacy_test_26" />
+        <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+        <option name="instrumentation-arg" key="expected-api-files" value="legacy-test-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
new file mode 100644
index 0000000..08cc051
--- /dev/null
+++ b/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2011 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.signature.cts.api;
+
+import android.os.Bundle;
+import android.signature.cts.ApiDocumentParser;
+import android.signature.cts.ApiComplianceChecker;
+import android.signature.cts.FailureType;
+import android.signature.cts.JDiffClassDescription;
+import android.signature.cts.ReflectionHelper;
+import android.signature.cts.ResultObserver;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
+import org.xmlpull.v1.XmlPullParserException;
+import repackaged.android.test.InstrumentationTestCase;
+import repackaged.android.test.InstrumentationTestRunner;
+
+import static android.signature.cts.CurrentApi.API_FILE_DIRECTORY;
+
+/**
+ * Performs the signature check via a JUnit test.
+ */
+public class SignatureTest extends InstrumentationTestCase {
+
+    private static final String TAG = SignatureTest.class.getSimpleName();
+
+    /**
+     * A set of class names that are inaccessible for some reason.
+     */
+    private static final Set<String> KNOWN_INACCESSIBLE_CLASSES = new HashSet<>();
+
+    static {
+        // TODO(b/63383787) - These classes, which are nested annotations with @Retention(SOURCE)
+        // are removed from framework.dex for an as yet unknown reason.
+        KNOWN_INACCESSIBLE_CLASSES.add("android.content.pm.PackageManager.PermissionFlags");
+        KNOWN_INACCESSIBLE_CLASSES.add("android.os.UserManager.UserRestrictionSource");
+        KNOWN_INACCESSIBLE_CLASSES.add(
+                "android.service.persistentdata.PersistentDataBlockManager.FlashLockState");
+    }
+
+    private TestResultObserver mResultObserver;
+
+    private String[] expectedApiFiles;
+    private String[] unexpectedApiFiles;
+
+    private class TestResultObserver implements ResultObserver {
+
+        boolean mDidFail = false;
+
+        StringBuilder mErrorString = new StringBuilder();
+
+        @Override
+        public void notifyFailure(FailureType type, String name, String errorMessage) {
+            mDidFail = true;
+            mErrorString.append("\n");
+            mErrorString.append(type.toString().toLowerCase());
+            mErrorString.append(":\t");
+            mErrorString.append(name);
+            mErrorString.append("\tError: ");
+            mErrorString.append(errorMessage);
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResultObserver = new TestResultObserver();
+
+        // Get the arguments passed to the instrumentation.
+        Bundle instrumentationArgs =
+                ((InstrumentationTestRunner) getInstrumentation()).getArguments();
+
+        expectedApiFiles = getCommaSeparatedList(instrumentationArgs, "expected-api-files");
+        unexpectedApiFiles = getCommaSeparatedList(instrumentationArgs, "unexpected-api-files");
+    }
+
+    private String[] getCommaSeparatedList(Bundle instrumentationArgs, String key) {
+        String argument = instrumentationArgs.getString(key);
+        if (argument == null) {
+            return new String[0];
+        }
+        return argument.split(",");
+    }
+
+    /**
+     * Tests that the device's API matches the expected set defined in xml.
+     * <p/>
+     * Will check the entire API, and then report the complete list of failures
+     */
+    public void testSignature() {
+        try {
+            Set<JDiffClassDescription> unexpectedClasses = loadUnexpectedClasses();
+            for (JDiffClassDescription classDescription : unexpectedClasses) {
+                Class<?> unexpectedClass = findUnexpectedClass(classDescription);
+                if (unexpectedClass != null) {
+                    mResultObserver.notifyFailure(
+                            FailureType.UNEXPECTED_CLASS,
+                            classDescription.getAbsoluteClassName(),
+                            "Class should not be accessible to this APK");
+                }
+            }
+
+            ApiComplianceChecker complianceChecker = new ApiComplianceChecker(mResultObserver);
+            ApiDocumentParser apiDocumentParser = new ApiDocumentParser(
+                    TAG, new ApiDocumentParser.Listener() {
+                @Override
+                public void completedClass(JDiffClassDescription classDescription) {
+                    // Ignore classes that are known to be inaccessible.
+                    if (KNOWN_INACCESSIBLE_CLASSES.contains(classDescription.getAbsoluteClassName())) {
+                        return;
+                    }
+
+                    // Ignore unexpected classes that are in the API definition.
+                    if (!unexpectedClasses.contains(classDescription)) {
+                        complianceChecker.checkSignatureCompliance(classDescription);
+                    }
+                }
+            });
+
+            for (String expectedApiFile : expectedApiFiles) {
+                File file = new File(API_FILE_DIRECTORY + "/" + expectedApiFile);
+                apiDocumentParser.parse(new FileInputStream(file));
+            }
+        } catch (Exception e) {
+            mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION, e.getMessage(),
+                    e.getMessage());
+        }
+        if (mResultObserver.mDidFail) {
+            StringBuilder errorString = mResultObserver.mErrorString;
+            ClassLoader classLoader = getClass().getClassLoader();
+            errorString.append("\nClassLoader hierarchy\n");
+            while (classLoader != null) {
+                errorString.append("    ").append(classLoader).append("\n");
+                classLoader = classLoader.getParent();
+            }
+            fail(errorString.toString());
+        }
+    }
+
+    private Class<?> findUnexpectedClass(JDiffClassDescription classDescription) {
+        try {
+            return ReflectionHelper.findMatchingClass(classDescription);
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    private Set<JDiffClassDescription> loadUnexpectedClasses()
+            throws IOException, XmlPullParserException {
+
+        Set<JDiffClassDescription> unexpectedClasses = new TreeSet<>(
+                Comparator.comparing(JDiffClassDescription::getAbsoluteClassName));
+        ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG,
+                new ApiDocumentParser.Listener() {
+                    @Override
+                    public void completedClass(JDiffClassDescription classDescription) {
+                        unexpectedClasses.add(classDescription);
+                    }
+                });
+        for (String expectedApiFile : unexpectedApiFiles) {
+            File file = new File(API_FILE_DIRECTORY + "/" + expectedApiFile);
+            apiDocumentParser.parse(new FileInputStream(file));
+        }
+        return unexpectedClasses;
+    }
+}
diff --git a/hostsidetests/jvmti/run-tests/test-981/Android.mk b/tests/signature/api-check/system-current-api/Android.mk
similarity index 65%
copy from hostsidetests/jvmti/run-tests/test-981/Android.mk
copy to tests/signature/api-check/system-current-api/Android.mk
index 151379b..1c10d2c 100644
--- a/hostsidetests/jvmti/run-tests/test-981/Android.mk
+++ b/tests/signature/api-check/system-current-api/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 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.
@@ -16,11 +16,11 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := CtsJvmtiRunTest981HostTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiHostTestBase
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_PACKAGE_NAME := CtsSystemCurrentApiSignatureTestCases
 
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_SIGNATURE_API_FILES := \
+    system-current.api \
+    android-test-mock-current.api \
+    android-test-runner-current.api \
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/api-check/system-current-api/AndroidManifest.xml
similarity index 72%
copy from tests/signature/AndroidManifest.xml
copy to tests/signature/api-check/system-current-api/AndroidManifest.xml
index 41a4233..d678c4b 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/api-check/system-current-api/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2008 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.
@@ -16,16 +16,14 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts">
+          package="android.signature.cts.api.system_current">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
-    <application>
-        <uses-library android:name="android.test.runner"/>
-    </application>
+    <application/>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature.cts"
-                     android:label="API Signature Test"/>
+    <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.signature.cts.api.system_current"
+                     android:label="System Current API Signature Test"/>
 
 </manifest>
diff --git a/tests/signature/api-check/system-current-api/AndroidTest.xml b/tests/signature/api-check/system-current-api/AndroidTest.xml
new file mode 100644
index 0000000..6bf641a
--- /dev/null
+++ b/tests/signature/api-check/system-current-api/AndroidTest.xml
@@ -0,0 +1,42 @@
+<?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 System Current API Signature test cases">
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <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="system-current.api->/data/local/tmp/signature-test/system-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="android-test-runner-current.api->/data/local/tmp/signature-test/android-test-runner-current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSystemCurrentApiSignatureTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.signature.cts.api.system_current" />
+        <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+        <option name="instrumentation-arg" key="expected-api-files" value="system-current.api" />
+        <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
+        <option name="runtime-hint" value="30s" />
+    </test>
+</configuration>
diff --git a/tests/signature/api/Android.mk b/tests/signature/api/Android.mk
index fed7d66..29328cb 100644
--- a/tests/signature/api/Android.mk
+++ b/tests/signature/api/Android.mk
@@ -14,7 +14,7 @@
 
 # We define this in a subdir so that it won't pick up the parent's Android.xml by default.
 
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
 # current api, in XML format.
@@ -23,35 +23,54 @@
 # by com.android.cts.managedprofile.CurrentApiHelper
 # ============================================================
 include $(CLEAR_VARS)
+
 LOCAL_MODULE := cts-current-api
 LOCAL_MODULE_STEM := current.api
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_ETC)
+LOCAL_SRC_FILES := frameworks/base/api/current.txt
 
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+include $(LOCAL_PATH)/build_xml_api_file.mk
 
-include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE) : frameworks/base/api/current.txt | $(APICHECK)
-	@echo "Convert API file $@"
-	@mkdir -p $(dir $@)
-	$(hide) $(APICHECK_COMMAND) -convert2xml $< $@
-
-include $(CLEAR_VARS)
-
-# current api, in XML format.
+# current system api, in XML format.
 # ============================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := cts-system-current-api
 LOCAL_MODULE_STEM := system-current.api
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_ETC)
+LOCAL_SRC_FILES := frameworks/base/api/system-current.txt
 
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+include $(LOCAL_PATH)/build_xml_api_file.mk
 
-include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE) : frameworks/base/api/system-current.txt | $(APICHECK)
-	@echo "Convert API file $@"
-	@mkdir -p $(dir $@)
-	$(hide) $(APICHECK_COMMAND) -convert2xml $< $@
+# current legacy-test api, in XML format.
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := cts-legacy-test-current-api
+LOCAL_MODULE_STEM := legacy-test-current.api
+LOCAL_SRC_FILES := frameworks/base/legacy-test/api/legacy-test-current.txt
+
+include $(LOCAL_PATH)/build_xml_api_file.mk
+
+# current android-test-mock api, in XML format.
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := cts-android-test-mock-current-api
+LOCAL_MODULE_STEM := android-test-mock-current.api
+LOCAL_SRC_FILES := frameworks/base/test-runner/api/android-test-mock-current.txt
+
+include $(LOCAL_PATH)/build_xml_api_file.mk
+
+# current android-test-runner api, in XML format.
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := cts-android-test-runner-current-api
+LOCAL_MODULE_STEM := android-test-runner-current.api
+LOCAL_SRC_FILES := frameworks/base/test-runner/api/android-test-runner-current.txt
+
+include $(LOCAL_PATH)/build_xml_api_file.mk
+
+# current apache-http-legacy api, in XML format.
+# ==============================================
+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
+
+include $(LOCAL_PATH)/build_xml_api_file.mk
diff --git a/tests/signature/api/build_xml_api_file.mk b/tests/signature/api/build_xml_api_file.mk
new file mode 100644
index 0000000..f5468bb
--- /dev/null
+++ b/tests/signature/api/build_xml_api_file.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.
+
+# Specify the following 3 variables before including:
+#
+#     LOCAL_MODULE_STEM
+#         the name of the file to generate, e.g. current.api
+#
+#     LOCAL_MODULE
+#         the name of the module - must be unique
+#
+#     LOCAL_SRC_FILES
+#         the name of the source api txt file - only one file allowed
+
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_ETC)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE) : ${LOCAL_SRC_FILES} | $(APICHECK)
+	@echo "Convert API file $< -> $@"
+	@mkdir -p $(dir $@)
+	$(hide) $(APICHECK_COMMAND) -convert2xmlnostrip $< $@
diff --git a/hostsidetests/devicepolicy/app/VpnApp/Android.mk b/tests/signature/intent-check/Android.mk
similarity index 67%
copy from hostsidetests/devicepolicy/app/VpnApp/Android.mk
copy to tests/signature/intent-check/Android.mk
index 9723b97..c251c3f 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/Android.mk
+++ b/tests/signature/intent-check/Android.mk
@@ -1,4 +1,4 @@
-# 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.
@@ -13,22 +13,23 @@
 # limitations under the License.
 
 LOCAL_PATH:= $(call my-dir)
-
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsVpnFirewallApp
-
+# don't include this package in any target
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_PACKAGE_NAME := CtsIntentSignatureTestCases
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    android-support-test \
+    cts-signature-common \
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/intent-check/AndroidManifest.xml
similarity index 85%
rename from tests/signature/AndroidManifest.xml
rename to tests/signature/intent-check/AndroidManifest.xml
index 41a4233..a444350 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/intent-check/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2008 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.
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts">
+          package="android.signature.cts.intent">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
@@ -25,7 +25,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature.cts"
-                     android:label="API Signature Test"/>
+                     android:targetPackage="android.signature.cts.intent"
+                     android:label="Intent Signature Test"/>
 
 </manifest>
diff --git a/tests/signature/AndroidTest.xml b/tests/signature/intent-check/AndroidTest.xml
similarity index 81%
rename from tests/signature/AndroidTest.xml
rename to tests/signature/intent-check/AndroidTest.xml
index 0ca8ce2..e53f5d8 100644
--- a/tests/signature/AndroidTest.xml
+++ b/tests/signature/intent-check/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
@@ -13,11 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Signature test cases">
+<configuration description="Config for CTS Intent Signature test cases">
     <option name="config-descriptor:metadata" key="component" value="systems" />
-   <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="device" />
-        <option name="config-filename" value="CtsSignatureTestCases" />
+        <option name="config-filename" value="CtsIntentSignatureTestCases" />
         <option name="version" value="1.0" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
@@ -38,10 +38,10 @@
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsSignatureTestCases.apk" />
+        <option name="test-file-name" value="CtsIntentSignatureTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.signature.cts" />
-        <option name="runtime-hint" value="7m11s" />
+        <option name="package" value="android.signature.cts.intent" />
+        <option name="runtime-hint" value="10s" />
     </test>
 </configuration>
diff --git a/tests/signature/DynamicConfig.xml b/tests/signature/intent-check/DynamicConfig.xml
similarity index 100%
rename from tests/signature/DynamicConfig.xml
rename to tests/signature/intent-check/DynamicConfig.xml
diff --git a/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java b/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
new file mode 100644
index 0000000..02ed487
--- /dev/null
+++ b/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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 android.signature.cts.intent;
+
+import static android.signature.cts.CurrentApi.CURRENT_API_FILE;
+import static android.signature.cts.CurrentApi.SYSTEM_CURRENT_API_FILE;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.signature.cts.ApiDocumentParser;
+import android.signature.cts.JDiffClassDescription;
+import android.signature.cts.JDiffClassDescription.JDiffField;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Assert;
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Validate that the android intents used by APKs on this device are part of the
+ * platform.
+ */
+@RunWith(AndroidJUnit4.class)
+public class IntentTest {
+    private static final String TAG = IntentTest.class.getSimpleName();
+
+    private static final File SIGNATURE_TEST_PACKGES =
+            new File("/data/local/tmp/signature-test-packages");
+    private static final String ANDROID_INTENT_PREFIX = "android.intent.action";
+    private static final String ACTION_LINE_PREFIX = "          Action: ";
+    private static final String MODULE_NAME = "CtsIntentSignatureTestCases";
+
+    private PackageManager mPackageManager;
+    private Set<String> intentWhitelist;
+
+    @Before
+    public void setupPackageManager() throws Exception {
+      mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
+      intentWhitelist = getIntentWhitelist();
+    }
+
+    @Test
+    public void shouldNotFindUnexpectedIntents() throws Exception {
+        Set<String> platformIntents = lookupPlatformIntents();
+        platformIntents.addAll(intentWhitelist);
+
+        Set<String> allInvalidIntents = new HashSet<>();
+
+        Set<String> errors = new HashSet<>();
+        List<ApplicationInfo> packages =
+            mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA);
+        for (ApplicationInfo appInfo : packages) {
+            if (!isSystemApp(appInfo) && !isUpdatedSystemApp(appInfo)) {
+                // Only examine system apps
+                continue;
+            }
+            Set<String> invalidIntents = new HashSet<>();
+            Set<String> activeIntents = lookupActiveIntents(appInfo.packageName);
+
+            for (String activeIntent : activeIntents) {
+              String intent = activeIntent.trim();
+              if (!platformIntents.contains(intent) &&
+                    intent.startsWith(ANDROID_INTENT_PREFIX)) {
+                  invalidIntents.add(activeIntent);
+                  allInvalidIntents.add(activeIntent);
+              }
+            }
+
+            String error = String.format("Package: %s Invalid Intent: %s",
+                  appInfo.packageName, invalidIntents);
+            if (!invalidIntents.isEmpty()) {
+                errors.add(error);
+            }
+        }
+
+        // Log the whitelist line to make it easy to update.
+        for (String intent : allInvalidIntents) {
+           Log.d(TAG, String.format("whitelist.add(\"%s\");", intent));
+        }
+
+        Assert.assertTrue(errors.toString(), errors.isEmpty());
+    }
+
+    private Set<String> lookupPlatformIntents() {
+        try {
+            Set<String> intents = new HashSet<>();
+            intents.addAll(parse(CURRENT_API_FILE));
+            intents.addAll(parse(SYSTEM_CURRENT_API_FILE));
+            return intents;
+        } catch (XmlPullParserException | IOException e) {
+            throw new RuntimeException("failed to parse", e);
+        }
+    }
+
+    private static Set<String> parse(String apiFileName)
+            throws XmlPullParserException, IOException {
+
+        Set<String> androidIntents = new HashSet<>();
+
+        ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG,
+                new ApiDocumentParser.Listener() {
+                    @Override
+                    public void completedClass(JDiffClassDescription classDescription) {
+                        for (JDiffField diffField : classDescription.getFieldList()) {
+                            String fieldValue = diffField.getValueString();
+                            if (fieldValue != null) {
+                                fieldValue = fieldValue.replace("\"", "");
+                                if (fieldValue.startsWith(ANDROID_INTENT_PREFIX)) {
+                                    androidIntents.add(fieldValue);
+                                }
+                            }
+                        }
+
+                    }
+                });
+
+        apiDocumentParser.parse(new FileInputStream(new File(apiFileName)));
+
+        return androidIntents;
+    }
+
+    private static boolean isSystemApp(ApplicationInfo applicationInfo) {
+        return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    private static boolean isUpdatedSystemApp(ApplicationInfo applicationInfo) {
+        return (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+    }
+
+    private static Set<String> lookupActiveIntents(String packageName) {
+        HashSet<String> activeIntents = new HashSet<>();
+        File dumpsysPackage = new File(SIGNATURE_TEST_PACKGES, packageName + ".txt");
+        if (!dumpsysPackage.exists() || dumpsysPackage.length() == 0) {
+          throw new RuntimeException("Missing package info: " + dumpsysPackage.getAbsolutePath());
+        }
+        try (
+            BufferedReader in = new BufferedReader(
+                  new InputStreamReader(new FileInputStream(dumpsysPackage)))) {
+            String line;
+            while ((line = in.readLine()) != null) {
+                if (line.startsWith(ACTION_LINE_PREFIX)) {
+                    String intent = line.substring(
+                          ACTION_LINE_PREFIX.length(), line.length() - 1);
+                    activeIntents.add(intent.replace("\"", ""));
+                }
+            }
+            return activeIntents;
+        } catch (Exception e) {
+          throw new RuntimeException("While retrieving dumpsys", e);
+        }
+    }
+
+    private static Set<String> getIntentWhitelist() throws Exception {
+        Set<String> whitelist = new HashSet<>();
+
+        DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(MODULE_NAME);
+        List<String> intentWhitelist = dcds.getValues("intent_whitelist");
+
+        // Log the whitelist Intent
+        for (String intent : intentWhitelist) {
+           Log.d(TAG, String.format("whitelist add: %s", intent));
+           whitelist.add(intent);
+        }
+
+        return whitelist;
+    }
+}
diff --git a/tests/signature/runSignatureTests.sh b/tests/signature/runSignatureTests.sh
new file mode 100755
index 0000000..623973d
--- /dev/null
+++ b/tests/signature/runSignatureTests.sh
@@ -0,0 +1,36 @@
+#! /bin/bash
+#
+# Copyright 2017 The Android Open Source Project.
+#
+# Builds and runs signature APK tests.
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    echo "Missing environment variables. Did you run build/envsetup.sh and lunch?" >&2
+    exit 1
+fi
+
+if [ $# -eq 0 ]; then
+    PACKAGES="
+CtsCurrentApiSignatureTestCases
+CtsSystemCurrentApiSignatureTestCases
+CtsAndroidTestMockCurrentApiSignatureTestCases
+CtsAndroidTestRunnerCurrentApiSignatureTestCases
+CtsLegacyTest26ApiSignatureTestCases
+CtsApacheHttpLegacyCurrentApiSignatureTestCases
+"
+else
+    PACKAGES=${1+"$@"}
+fi
+
+cd $ANDROID_BUILD_TOP
+make -j32 $PACKAGES
+
+TMPFILE=$(mktemp)
+trap "echo Removing temporary directory; rm -f $TMPFILE" EXIT
+
+for p in $PACKAGES
+do
+    echo cts -a arm64-v8a -m "$p" >> $TMPFILE
+done
+
+cts-tradefed run cmdfileAndExit $TMPFILE
diff --git a/tests/signature/src/android/signature/cts/ApiComplianceChecker.java b/tests/signature/src/android/signature/cts/ApiComplianceChecker.java
new file mode 100644
index 0000000..8dbf5e7
--- /dev/null
+++ b/tests/signature/src/android/signature/cts/ApiComplianceChecker.java
@@ -0,0 +1,744 @@
+/*
+ * 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.signature.cts;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Checks that the runtime representation of a class matches the API representation of a class.
+ */
+public class ApiComplianceChecker {
+
+    /** Indicates that the class is an annotation. */
+    private static final int CLASS_MODIFIER_ANNOTATION = 0x00002000;
+
+    /** Indicates that the class is an enum. */
+    private static final int CLASS_MODIFIER_ENUM       = 0x00004000;
+
+    /** Indicates that the method is a bridge method. */
+    private static final int METHOD_MODIFIER_BRIDGE    = 0x00000040;
+
+    /** Indicates that the method is takes a variable number of arguments. */
+    private static final int METHOD_MODIFIER_VAR_ARGS  = 0x00000080;
+
+    /** Indicates that the method is a synthetic method. */
+    private static final int METHOD_MODIFIER_SYNTHETIC = 0x00001000;
+
+    private static final Set<String> HIDDEN_INTERFACE_WHITELIST = new HashSet<>();
+
+    static {
+        // Interfaces that define @hide or @SystemApi or @TestApi methods will by definition contain
+        // methods that do not appear in current.txt. Interfaces added to this
+        // list are probably not meant to be implemented in an application.
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract boolean android.companion.DeviceFilter.matches(D)");
+        HIDDEN_INTERFACE_WHITELIST.add("public static <D> boolean android.companion.DeviceFilter.matches(android.companion.DeviceFilter<D>,D)");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract java.lang.String android.companion.DeviceFilter.getDeviceDisplayName(D)");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract int android.companion.DeviceFilter.getMediumType()");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.nfc.tech.TagTechnology.reconnect() throws java.io.IOException");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.os.IBinder.shellCommand(java.io.FileDescriptor,java.io.FileDescriptor,java.io.FileDescriptor,java.lang.String[],android.os.ShellCallback,android.os.ResultReceiver) throws android.os.RemoteException");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract int android.text.ParcelableSpan.getSpanTypeIdInternal()");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.text.ParcelableSpan.writeToParcelInternal(android.os.Parcel,int)");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.view.WindowManager.requestAppKeyboardShortcuts(android.view.WindowManager$KeyboardShortcutsReceiver,int)");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract boolean javax.microedition.khronos.egl.EGL10.eglReleaseThread()");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract void org.w3c.dom.ls.LSSerializer.setFilter(org.w3c.dom.ls.LSSerializerFilter)");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract org.w3c.dom.ls.LSSerializerFilter org.w3c.dom.ls.LSSerializer.getFilter()");
+        HIDDEN_INTERFACE_WHITELIST.add("public abstract android.graphics.Region android.view.WindowManager.getCurrentImeTouchRegion()");
+    }
+
+
+    private final ResultObserver resultObserver;
+
+    public ApiComplianceChecker(ResultObserver resultObserver) {
+        this.resultObserver = resultObserver;
+    }
+
+    private static void loge(String message, Exception exception) {
+        System.err.println(String.format("%s: %s", message, exception));
+    }
+
+    private void logMismatchInterfaceSignature(JDiffClassDescription.JDiffType mClassType,
+            String classFullName, String errorMessage) {
+        if (JDiffClassDescription.JDiffType.INTERFACE.equals(mClassType)) {
+            resultObserver.notifyFailure(FailureType.MISMATCH_INTERFACE,
+                    classFullName,
+                    errorMessage);
+        } else {
+            resultObserver.notifyFailure(FailureType.MISMATCH_CLASS,
+                    classFullName,
+                    errorMessage);
+        }
+    }
+
+    /**
+     * Checks test class's name, modifier, fields, constructors, and
+     * methods.
+     */
+    public void checkSignatureCompliance(JDiffClassDescription classDescription) {
+        Class<?> runtimeClass = checkClassCompliance(classDescription);
+        if (runtimeClass != null) {
+            checkFieldsCompliance(classDescription, runtimeClass);
+            checkConstructorCompliance(classDescription, runtimeClass);
+            checkMethodCompliance(classDescription, runtimeClass);
+        }
+    }
+
+    /**
+     * Checks that the class found through reflection matches the
+     * specification from the API xml file.
+     *
+     * @param classDescription a description of a class in an API.
+     */
+    @SuppressWarnings("unchecked")
+    private Class<?> checkClassCompliance(JDiffClassDescription classDescription) {
+        try {
+            Class<?> runtimeClass = findRequiredClass(classDescription);
+
+            if (runtimeClass == null) {
+                // No class found, notify the observer according to the class type
+                if (JDiffClassDescription.JDiffType.INTERFACE.equals(
+                        classDescription.getClassType())) {
+                    resultObserver.notifyFailure(FailureType.MISSING_INTERFACE,
+                            classDescription.getAbsoluteClassName(),
+                            "Classloader is unable to find " + classDescription
+                                    .getAbsoluteClassName());
+                } else {
+                    resultObserver.notifyFailure(FailureType.MISSING_CLASS,
+                            classDescription.getAbsoluteClassName(),
+                            "Classloader is unable to find " + classDescription
+                                    .getAbsoluteClassName());
+                }
+
+                return null;
+            }
+
+            List<String> methods = checkInterfaceMethodCompliance(classDescription, runtimeClass);
+            if (JDiffClassDescription.JDiffType.INTERFACE.equals(classDescription.getClassType()) && methods.size() > 0) {
+                resultObserver.notifyFailure(FailureType.MISMATCH_INTERFACE_METHOD,
+                        classDescription.getAbsoluteClassName(), "Interfaces cannot be modified: "
+                                + classDescription.getAbsoluteClassName() + ": " + methods);
+                return null;
+            }
+
+            if (!checkClassModifiersCompliance(classDescription, runtimeClass)) {
+                logMismatchInterfaceSignature(classDescription.getClassType(),
+                        classDescription.getAbsoluteClassName(),
+                                "Non-compatible class found when looking for " +
+                                        classDescription.toSignatureString());
+                return null;
+            }
+
+            if (!checkClassAnnotationCompliance(classDescription, runtimeClass)) {
+                logMismatchInterfaceSignature(classDescription.getClassType(),
+                        classDescription.getAbsoluteClassName(),
+                                "Annotation mismatch");
+                return null;
+            }
+
+            if (!runtimeClass.isAnnotation()) {
+                // check father class
+                if (!checkClassExtendsCompliance(classDescription, runtimeClass)) {
+                    logMismatchInterfaceSignature(classDescription.getClassType(),
+                            classDescription.getAbsoluteClassName(),
+                                    "Extends mismatch");
+                    return null;
+                }
+
+                // check implements interface
+                if (!checkClassImplementsCompliance(classDescription, runtimeClass)) {
+                    logMismatchInterfaceSignature(classDescription.getClassType(),
+                            classDescription.getAbsoluteClassName(),
+                                    "Implements mismatch");
+                    return null;
+                }
+            }
+            return runtimeClass;
+        } catch (Exception e) {
+            loge("Got exception when checking field compliance", e);
+            resultObserver.notifyFailure(
+                    FailureType.CAUGHT_EXCEPTION,
+                    classDescription.getAbsoluteClassName(),
+                    "Exception!");
+            return null;
+        }
+    }
+
+    private Class<?> findRequiredClass(JDiffClassDescription classDescription) {
+        try {
+            return ReflectionHelper.findMatchingClass(classDescription);
+        } catch (ClassNotFoundException e) {
+            loge("ClassNotFoundException for " + classDescription.getAbsoluteClassName(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Validate that an interfaces method count is as expected.
+     *
+     * @param classDescription the class's API description.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     */
+    private static List<String> checkInterfaceMethodCompliance(
+            JDiffClassDescription classDescription, Class<?> runtimeClass) {
+        List<String> unexpectedMethods = new ArrayList<>();
+        for (Method method : runtimeClass.getDeclaredMethods()) {
+            if (method.isDefault()) {
+                continue;
+            }
+            if (method.isSynthetic()) {
+                continue;
+            }
+            if (method.isBridge()) {
+                continue;
+            }
+            if (HIDDEN_INTERFACE_WHITELIST.contains(method.toGenericString())) {
+                continue;
+            }
+
+            boolean foundMatch = false;
+            for (JDiffClassDescription.JDiffMethod jdiffMethod : classDescription.getMethods()) {
+                if (ReflectionHelper.matches(jdiffMethod, method)) {
+                    foundMatch = true;
+                }
+            }
+            if (!foundMatch) {
+                unexpectedMethods.add(method.toGenericString());
+            }
+        }
+
+        return unexpectedMethods;
+
+    }
+
+    /**
+     * Checks if the class under test has compliant modifiers compared to the API.
+     *
+     * @param classDescription a description of a class in an API.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     * @return true if modifiers are compliant.
+     */
+    private static boolean checkClassModifiersCompliance(JDiffClassDescription classDescription,
+            Class<?> runtimeClass) {
+        int reflectionModifier = runtimeClass.getModifiers();
+        int apiModifier = classDescription.getModifier();
+
+        // If the api class isn't abstract
+        if (((apiModifier & Modifier.ABSTRACT) == 0) &&
+                // but the reflected class is
+                ((reflectionModifier & Modifier.ABSTRACT) != 0) &&
+                // and it isn't an enum
+                !classDescription.isEnumType()) {
+            // that is a problem
+            return false;
+        }
+        // ABSTRACT check passed, so mask off ABSTRACT
+        reflectionModifier &= ~Modifier.ABSTRACT;
+        apiModifier &= ~Modifier.ABSTRACT;
+
+        if (classDescription.isAnnotation()) {
+            reflectionModifier &= ~CLASS_MODIFIER_ANNOTATION;
+        }
+        if (runtimeClass.isInterface()) {
+            reflectionModifier &= ~(Modifier.INTERFACE);
+        }
+        if (classDescription.isEnumType() && runtimeClass.isEnum()) {
+            reflectionModifier &= ~CLASS_MODIFIER_ENUM;
+        }
+
+        return ((reflectionModifier == apiModifier) &&
+                (classDescription.isEnumType() == runtimeClass.isEnum()));
+    }
+
+    /**
+     * Checks if the class under test is compliant with regards to
+     * annnotations when compared to the API.
+     *
+     * @param classDescription a description of a class in an API.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     * @return true if the class is compliant
+     */
+    private static boolean checkClassAnnotationCompliance(JDiffClassDescription classDescription,
+            Class<?> runtimeClass) {
+        if (runtimeClass.isAnnotation()) {
+            // check annotation
+            for (String inter : classDescription.getImplInterfaces()) {
+                if ("java.lang.annotation.Annotation".equals(inter)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Checks if the class under test extends the proper classes
+     * according to the API.
+     *
+     * @param classDescription a description of a class in an API.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     * @return true if the class is compliant.
+     */
+    private static boolean checkClassExtendsCompliance(JDiffClassDescription classDescription,
+            Class<?> runtimeClass) {
+        // Nothing to check if it doesn't extend anything.
+        if (classDescription.getExtendedClass() != null) {
+            Class<?> superClass = runtimeClass.getSuperclass();
+
+            while (superClass != null) {
+                if (superClass.getCanonicalName().equals(classDescription.getExtendedClass())) {
+                    return true;
+                }
+                superClass = superClass.getSuperclass();
+            }
+            // Couldn't find a matching superclass.
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Checks if the class under test implements the proper interfaces
+     * according to the API.
+     *
+     * @param classDescription a description of a class in an API.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     * @return true if the class is compliant
+     */
+    private static boolean checkClassImplementsCompliance(JDiffClassDescription classDescription,
+            Class<?> runtimeClass) {
+        Class<?>[] interfaces = runtimeClass.getInterfaces();
+        Set<String> interFaceSet = new HashSet<>();
+
+        for (Class<?> c : interfaces) {
+            interFaceSet.add(c.getCanonicalName());
+        }
+
+        for (String inter : classDescription.getImplInterfaces()) {
+            if (!interFaceSet.contains(inter)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    /**
+     * Checks all fields in test class for compliance with the API xml.
+     *
+     * @param classDescription a description of a class in an API.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     */
+    @SuppressWarnings("unchecked")
+    private void checkFieldsCompliance(JDiffClassDescription classDescription,
+            Class<?> runtimeClass) {
+        // A map of field name to field of the fields contained in runtimeClass.
+        Map<String, Field> classFieldMap = buildFieldMap(runtimeClass);
+        for (JDiffClassDescription.JDiffField field : classDescription.getFields()) {
+            try {
+                Field f = classFieldMap.get(field.mName);
+                if (f == null) {
+                    resultObserver.notifyFailure(FailureType.MISSING_FIELD,
+                            field.toReadableString(classDescription.getAbsoluteClassName()),
+                            "No field with correct signature found:" +
+                                    field.toSignatureString());
+                } else if (f.getModifiers() != field.mModifier) {
+                    resultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
+                            field.toReadableString(classDescription.getAbsoluteClassName()),
+                            "Non-compatible field modifiers found when looking for " +
+                                    field.toSignatureString());
+                } else if (!checkFieldValueCompliance(field, f)) {
+                    resultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
+                            field.toReadableString(classDescription.getAbsoluteClassName()),
+                            "Incorrect field value found when looking for " +
+                                    field.toSignatureString());
+                } else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
+                    // type name does not match, but this might be a generic
+                    String genericTypeName = null;
+                    Type type = f.getGenericType();
+                    if (type != null) {
+                        genericTypeName = type instanceof Class ? ((Class) type).getName() :
+                                type.toString().replace('$', '.');
+                    }
+                    if (genericTypeName == null || !genericTypeName.equals(field.mFieldType)) {
+                        resultObserver.notifyFailure(
+                                FailureType.MISMATCH_FIELD,
+                                field.toReadableString(classDescription.getAbsoluteClassName()),
+                                "Non-compatible field type found when looking for " +
+                                        field.toSignatureString());
+                    }
+                }
+
+            } catch (Exception e) {
+                loge("Got exception when checking field compliance", e);
+                resultObserver.notifyFailure(
+                        FailureType.CAUGHT_EXCEPTION,
+                        field.toReadableString(classDescription.getAbsoluteClassName()),
+                        "Exception!");
+            }
+        }
+    }
+
+    /**
+     * Checks whether the field values are compatible.
+     *
+     * @param apiField The field as defined by the platform API.
+     * @param deviceField The field as defined by the device under test.
+     */
+    private static boolean checkFieldValueCompliance(JDiffClassDescription.JDiffField apiField, Field deviceField)
+            throws IllegalAccessException {
+        if ((apiField.mModifier & Modifier.FINAL) == 0 ||
+                (apiField.mModifier & Modifier.STATIC) == 0) {
+            // Only final static fields can have fixed values.
+            return true;
+        }
+        if (apiField.getValueString() == null) {
+            // If we don't define a constant value for it, then it can be anything.
+            return true;
+        }
+        // Some fields may be protected or package-private
+        deviceField.setAccessible(true);
+        switch (apiField.mFieldType) {
+            case "byte":
+                return Objects.equals(apiField.getValueString(),
+                        Byte.toString(deviceField.getByte(null)));
+            case "char":
+                return Objects.equals(apiField.getValueString(),
+                        Integer.toString(deviceField.getChar(null)));
+            case "short":
+                return Objects.equals(apiField.getValueString(),
+                        Short.toString(deviceField.getShort(null)));
+            case "int":
+                return Objects.equals(apiField.getValueString(),
+                        Integer.toString(deviceField.getInt(null)));
+            case "long":
+                return Objects.equals(apiField.getValueString(),
+                        Long.toString(deviceField.getLong(null)) + "L");
+            case "float":
+                return Objects.equals(apiField.getValueString(),
+                        canonicalizeFloatingPoint(
+                                Float.toString(deviceField.getFloat(null)), "f"));
+            case "double":
+                return Objects.equals(apiField.getValueString(),
+                        canonicalizeFloatingPoint(
+                                Double.toString(deviceField.getDouble(null)), ""));
+            case "boolean":
+                return Objects.equals(apiField.getValueString(),
+                        Boolean.toString(deviceField.getBoolean(null)));
+            case "java.lang.String":
+                String value = apiField.getValueString();
+                // Remove the quotes the value string is wrapped in
+                value = unescapeFieldStringValue(value.substring(1, value.length() - 1));
+                return Objects.equals(value, deviceField.get(null));
+            default:
+                return true;
+        }
+    }
+
+    /**
+     * Canonicalize the string representation of floating point numbers.
+     *
+     * This needs to be kept in sync with the doclava canonicalization.
+     */
+    private static String canonicalizeFloatingPoint(String val, String suffix) {
+        switch (val) {
+            case "Infinity":
+                return "(1.0" + suffix + "/0.0" + suffix + ")";
+            case "-Infinity":
+                return "(-1.0" + suffix + "/0.0" + suffix + ")";
+            case "NaN":
+                return "(0.0" + suffix + "/0.0" + suffix + ")";
+        }
+
+        if (val.indexOf('E') != -1) {
+            return val + suffix;
+        }
+
+        // 1.0 is the only case where a trailing "0" is allowed.
+        // 1.00 is canonicalized as 1.0.
+        int i = val.length() - 1;
+        int d = val.indexOf('.');
+        while (i >= d + 2 && val.charAt(i) == '0') {
+            val = val.substring(0, i--);
+        }
+        return val + suffix;
+    }
+
+    // This unescapes the string format used by doclava and so needs to be kept in sync with any
+    // changes made to that format.
+    private static String unescapeFieldStringValue(String str) {
+        final int N = str.length();
+
+        // If there's no special encoding strings in the string then just return it.
+        if (str.indexOf('\\') == -1) {
+            return str;
+        }
+
+        final StringBuilder buf = new StringBuilder(str.length());
+        char escaped = 0;
+        final int START = 0;
+        final int CHAR1 = 1;
+        final int CHAR2 = 2;
+        final int CHAR3 = 3;
+        final int CHAR4 = 4;
+        final int ESCAPE = 5;
+        int state = START;
+
+        for (int i = 0; i < N; i++) {
+            final char c = str.charAt(i);
+            switch (state) {
+                case START:
+                    if (c == '\\') {
+                        state = ESCAPE;
+                    } else {
+                        buf.append(c);
+                    }
+                    break;
+                case ESCAPE:
+                    switch (c) {
+                        case '\\':
+                            buf.append('\\');
+                            state = START;
+                            break;
+                        case 't':
+                            buf.append('\t');
+                            state = START;
+                            break;
+                        case 'b':
+                            buf.append('\b');
+                            state = START;
+                            break;
+                        case 'r':
+                            buf.append('\r');
+                            state = START;
+                            break;
+                        case 'n':
+                            buf.append('\n');
+                            state = START;
+                            break;
+                        case 'f':
+                            buf.append('\f');
+                            state = START;
+                            break;
+                        case '\'':
+                            buf.append('\'');
+                            state = START;
+                            break;
+                        case '\"':
+                            buf.append('\"');
+                            state = START;
+                            break;
+                        case 'u':
+                            state = CHAR1;
+                            escaped = 0;
+                            break;
+                    }
+                    break;
+                case CHAR1:
+                case CHAR2:
+                case CHAR3:
+                case CHAR4:
+                    escaped <<= 4;
+                    if (c >= '0' && c <= '9') {
+                        escaped |= c - '0';
+                    } else if (c >= 'a' && c <= 'f') {
+                        escaped |= 10 + (c - 'a');
+                    } else if (c >= 'A' && c <= 'F') {
+                        escaped |= 10 + (c - 'A');
+                    } else {
+                        throw new RuntimeException(
+                                "bad escape sequence: '" + c + "' at pos " + i + " in: \""
+                                        + str + "\"");
+                    }
+                    if (state == CHAR4) {
+                        buf.append(escaped);
+                        state = START;
+                    } else {
+                        state++;
+                    }
+                    break;
+            }
+        }
+        if (state != START) {
+            throw new RuntimeException("unfinished escape sequence: " + str);
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Scan a class (an its entire inheritance chain) for fields.
+     *
+     * @return a {@link Map} of fieldName to {@link Field}
+     */
+    private static Map<String, Field> buildFieldMap(Class testClass) {
+        Map<String, Field> fieldMap = new HashMap<>();
+        // Scan the superclass
+        if (testClass.getSuperclass() != null) {
+            fieldMap.putAll(buildFieldMap(testClass.getSuperclass()));
+        }
+
+        // Scan the interfaces
+        for (Class interfaceClass : testClass.getInterfaces()) {
+            fieldMap.putAll(buildFieldMap(interfaceClass));
+        }
+
+        // Check the fields in the test class
+        for (Field field : testClass.getDeclaredFields()) {
+            fieldMap.put(field.getName(), field);
+        }
+
+        return fieldMap;
+    }
+
+    /**
+     * Checks whether the constructor parsed from API xml file and
+     * Java reflection are compliant.
+     *
+     * @param classDescription a description of a class in an API.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     */
+    @SuppressWarnings("unchecked")
+    private void checkConstructorCompliance(JDiffClassDescription classDescription,
+            Class<?> runtimeClass) {
+        for (JDiffClassDescription.JDiffConstructor con : classDescription.getConstructors()) {
+            try {
+                Constructor<?> c = ReflectionHelper.findMatchingConstructor(runtimeClass, con);
+                if (c == null) {
+                    resultObserver.notifyFailure(FailureType.MISSING_METHOD,
+                            con.toReadableString(classDescription.getAbsoluteClassName()),
+                            "No method with correct signature found:" +
+                                    con.toSignatureString());
+                } else {
+                    if (c.isVarArgs()) {// some method's parameter are variable args
+                        con.mModifier |= METHOD_MODIFIER_VAR_ARGS;
+                    }
+                    if (c.getModifiers() != con.mModifier) {
+                        resultObserver.notifyFailure(
+                                FailureType.MISMATCH_METHOD,
+                                con.toReadableString(classDescription.getAbsoluteClassName()),
+                                "Non-compatible method found when looking for " +
+                                        con.toSignatureString());
+                    }
+                }
+            } catch (Exception e) {
+                loge("Got exception when checking constructor compliance", e);
+                resultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION,
+                        con.toReadableString(classDescription.getAbsoluteClassName()),
+                        "Exception!");
+            }
+        }
+    }
+
+    /**
+     * Checks that the method found through reflection matches the
+     * specification from the API xml file.
+     *
+     * @param classDescription a description of a class in an API.
+     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
+     */
+    private void checkMethodCompliance(JDiffClassDescription classDescription,
+            Class<?> runtimeClass) {
+        for (JDiffClassDescription.JDiffMethod method : classDescription.getMethods()) {
+            try {
+
+                Method m = ReflectionHelper.findMatchingMethod(runtimeClass, method);
+                if (m == null) {
+                    resultObserver.notifyFailure(FailureType.MISSING_METHOD,
+                            method.toReadableString(classDescription.getAbsoluteClassName()),
+                            "No method with correct signature found:" +
+                                    method.toSignatureString());
+                } else {
+                    if (m.isVarArgs()) {
+                        method.mModifier |= METHOD_MODIFIER_VAR_ARGS;
+                    }
+                    if (m.isBridge()) {
+                        method.mModifier |= METHOD_MODIFIER_BRIDGE;
+                    }
+                    if (m.isSynthetic()) {
+                        method.mModifier |= METHOD_MODIFIER_SYNTHETIC;
+                    }
+
+                    // FIXME: A workaround to fix the final mismatch on enumeration
+                    if (runtimeClass.isEnum() && method.mName.equals("values")) {
+                        return;
+                    }
+
+                    if (!areMethodsModifiedCompatible(classDescription, method, m)) {
+                        resultObserver.notifyFailure(FailureType.MISMATCH_METHOD,
+                                method.toReadableString(classDescription.getAbsoluteClassName()),
+                                "Non-compatible method found when looking for " +
+                                        method.toSignatureString());
+                    }
+                }
+            } catch (Exception e) {
+                loge("Got exception when checking method compliance", e);
+                resultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION,
+                        method.toReadableString(classDescription.getAbsoluteClassName()),
+                        "Exception!");
+            }
+        }
+    }
+
+    /**
+     * Checks to ensure that the modifiers value for two methods are compatible.
+     *
+     * Allowable differences are:
+     *   - synchronized is allowed to be removed from an apiMethod
+     *     that has it
+     *   - the native modified is ignored
+     *
+     * @param classDescription a description of a class in an API.
+     * @param apiMethod the method read from the api file.
+     * @param reflectedMethod the method found via reflection.
+     */
+    private static boolean areMethodsModifiedCompatible(
+            JDiffClassDescription classDescription,
+            JDiffClassDescription.JDiffMethod apiMethod,
+            Method reflectedMethod) {
+
+        // If the apiMethod isn't synchronized
+        if (((apiMethod.mModifier & Modifier.SYNCHRONIZED) == 0) &&
+                // but the reflected method is
+                ((reflectedMethod.getModifiers() & Modifier.SYNCHRONIZED) != 0)) {
+            // that is a problem
+            return false;
+        }
+
+        // Mask off NATIVE since it is a don't care.  Also mask off
+        // SYNCHRONIZED since we've already handled that check.
+        int ignoredMods = (Modifier.NATIVE | Modifier.SYNCHRONIZED | Modifier.STRICT);
+        int mod1 = reflectedMethod.getModifiers() & ~ignoredMods;
+        int mod2 = apiMethod.mModifier & ~ignoredMods;
+
+        // We can ignore FINAL for classes
+        if ((classDescription.getModifier() & Modifier.FINAL) != 0) {
+            mod1 &= ~Modifier.FINAL;
+            mod2 &= ~Modifier.FINAL;
+        }
+
+        return mod1 == mod2;
+    }
+}
diff --git a/tests/signature/src/android/signature/cts/ApiDocumentParser.java b/tests/signature/src/android/signature/cts/ApiDocumentParser.java
new file mode 100644
index 0000000..6c8b172
--- /dev/null
+++ b/tests/signature/src/android/signature/cts/ApiDocumentParser.java
@@ -0,0 +1,201 @@
+/*
+ * 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.signature.cts;
+
+import static android.signature.cts.CurrentApi.ATTRIBUTE_NAME;
+import static android.signature.cts.CurrentApi.ATTRIBUTE_TYPE;
+import static android.signature.cts.CurrentApi.TAG_CLASS;
+import static android.signature.cts.CurrentApi.TAG_CONSTRUCTOR;
+import static android.signature.cts.CurrentApi.TAG_EXCEPTION;
+import static android.signature.cts.CurrentApi.TAG_FIELD;
+import static android.signature.cts.CurrentApi.TAG_IMPLEMENTS;
+import static android.signature.cts.CurrentApi.TAG_INTERFACE;
+import static android.signature.cts.CurrentApi.TAG_METHOD;
+import static android.signature.cts.CurrentApi.TAG_PACKAGE;
+import static android.signature.cts.CurrentApi.TAG_PARAM;
+import static android.signature.cts.CurrentApi.TAG_ROOT;
+
+import android.util.Log;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+/**
+ * Parses an XML api definition file and constructs and populates an {@link JDiffClassDescription}
+ * for every class.
+ *
+ * <p>Once it has completely populated the members (so does not include nested/inner classes) of a
+ * {@link JDiffClassDescription} it notifies the {@link #listener} by calling
+ * {@link Listener#completedClass(JDiffClassDescription)} with the completed
+ * {@link JDiffClassDescription}.
+ */
+public class ApiDocumentParser {
+
+    private static final Set<String> KEY_TAG_SET;
+    static {
+        KEY_TAG_SET = new HashSet<>();
+        Collections.addAll(KEY_TAG_SET,
+                TAG_PACKAGE,
+                TAG_CLASS,
+                TAG_INTERFACE,
+                TAG_IMPLEMENTS,
+                TAG_CONSTRUCTOR,
+                TAG_METHOD,
+                TAG_PARAM,
+                TAG_EXCEPTION,
+                TAG_FIELD);
+    }
+
+    private final String tag;
+
+    private final Listener listener;
+
+    private final XmlPullParser parser;
+
+    public ApiDocumentParser(String tag, Listener listener) throws XmlPullParserException {
+        this.tag = tag;
+        this.listener = listener;
+
+        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        parser = factory.newPullParser();
+    }
+
+    public void parse(InputStream inputStream) throws XmlPullParserException, IOException {
+        parser.setInput(inputStream, null);
+        start(parser);
+    }
+
+    public interface Listener {
+
+        /**
+         * Invoked when a {@link JDiffClassDescription} has been completely populated.
+         *
+         * @param classDescription the description of the class as read from the XML API file.
+         */
+        void completedClass(JDiffClassDescription classDescription);
+    }
+
+
+    private void beginDocument(XmlPullParser parser, String firstElementName)
+            throws XmlPullParserException, IOException {
+        int type;
+        do {
+            type = parser.next();
+        } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT);
+
+        if (type != XmlPullParser.START_TAG) {
+            throw new XmlPullParserException("No start tag found");
+        }
+
+        if (!parser.getName().equals(firstElementName)) {
+            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
+                    ", expected " + firstElementName);
+        }
+    }
+
+    /**
+     * Signature test entry point.
+     */
+    private void start(XmlPullParser parser) throws XmlPullParserException, IOException {
+        logd(String.format("Name: %s", parser.getName()));
+        logd(String.format("Text: %s", parser.getText()));
+        logd(String.format("Namespace: %s", parser.getNamespace()));
+        logd(String.format("Line Number: %s", parser.getLineNumber()));
+        logd(String.format("Column Number: %s", parser.getColumnNumber()));
+        logd(String.format("Position Description: %s", parser.getPositionDescription()));
+        JDiffClassDescription currentClass = null;
+        String currentPackage = "";
+        JDiffClassDescription.JDiffMethod currentMethod = null;
+
+        beginDocument(parser, TAG_ROOT);
+        int type;
+        while (true) {
+            do {
+                type = parser.next();
+            } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.END_TAG);
+
+            if (type == XmlPullParser.END_TAG) {
+                if (TAG_CLASS.equals(parser.getName())
+                        || TAG_INTERFACE.equals(parser.getName())) {
+                    if (listener != null) {
+                        listener.completedClass(currentClass);
+                    }
+                } else if (TAG_PACKAGE.equals(parser.getName())) {
+                    currentPackage = "";
+                }
+                continue;
+            }
+
+            if (type == XmlPullParser.END_DOCUMENT) {
+                break;
+            }
+
+            String tagname = parser.getName();
+            if (!KEY_TAG_SET.contains(tagname)) {
+                continue;
+            }
+
+            if (type == XmlPullParser.START_TAG && tagname.equals(TAG_PACKAGE)) {
+                currentPackage = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+            } else if (tagname.equals(TAG_CLASS)) {
+                currentClass = CurrentApi.loadClassInfo(
+                        parser, false, currentPackage);
+            } else if (tagname.equals(TAG_INTERFACE)) {
+                currentClass = CurrentApi.loadClassInfo(
+                        parser, true, currentPackage);
+            } else if (tagname.equals(TAG_IMPLEMENTS)) {
+                currentClass.addImplInterface(parser.getAttributeValue(null, ATTRIBUTE_NAME));
+            } else if (tagname.equals(TAG_CONSTRUCTOR)) {
+                JDiffClassDescription.JDiffConstructor constructor =
+                        CurrentApi.loadConstructorInfo(parser, currentClass);
+                currentClass.addConstructor(constructor);
+                currentMethod = constructor;
+            } else if (tagname.equals(TAG_METHOD)) {
+                currentMethod = CurrentApi.loadMethodInfo(currentClass.getClassName(), parser);
+                currentClass.addMethod(currentMethod);
+            } else if (tagname.equals(TAG_PARAM)) {
+                currentMethod.addParam(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
+            } else if (tagname.equals(TAG_EXCEPTION)) {
+                currentMethod.addException(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
+            } else if (tagname.equals(TAG_FIELD)) {
+                JDiffClassDescription.JDiffField field = CurrentApi.loadFieldInfo(currentClass.getClassName(), parser);
+                currentClass.addField(field);
+            } else {
+                throw new RuntimeException(
+                        "unknown tag exception:" + tagname);
+            }
+            if (currentPackage != null) {
+                logd(String.format("currentPackage: %s", currentPackage));
+            }
+            if (currentClass != null) {
+                logd(String.format("currentClass: %s", currentClass.toSignatureString()));
+            }
+            if (currentMethod != null) {
+                logd(String.format("currentMethod: %s", currentMethod.toSignatureString()));
+            }
+        }
+    }
+
+    private void logd(String msg) {
+        Log.d(tag, msg);
+    }
+}
diff --git a/tests/signature/src/android/signature/cts/CurrentApi.java b/tests/signature/src/android/signature/cts/CurrentApi.java
index 4c48f9f..a09c1b8 100644
--- a/tests/signature/src/android/signature/cts/CurrentApi.java
+++ b/tests/signature/src/android/signature/cts/CurrentApi.java
@@ -22,20 +22,20 @@
 import java.lang.reflect.Modifier;
 
 import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
 
 /**
  * Helper methods and constants used for parsing the current api file.
  */
-class CurrentApi {
+public class CurrentApi {
 
     private CurrentApi() {}
 
-    static final String CURRENT_API_FILE =
-            "/data/local/tmp/signature-test/current.api";
-    static final String SYSTEM_CURRENT_API_FILE =
-            "/data/local/tmp/signature-test/system-current.api";
+    public static final String API_FILE_DIRECTORY = "/data/local/tmp/signature-test";
+
+    public static final String CURRENT_API_FILE =
+            API_FILE_DIRECTORY + "/current.api";
+    public static final String SYSTEM_CURRENT_API_FILE =
+            API_FILE_DIRECTORY + "/system-current.api";
 
     static final String TAG_ROOT = "api";
     static final String TAG_PACKAGE = "package";
@@ -48,23 +48,23 @@
     static final String TAG_EXCEPTION = "exception";
     static final String TAG_FIELD = "field";
 
-    static final String MODIFIER_ABSTRACT = "abstract";
-    static final String MODIFIER_FINAL = "final";
-    static final String MODIFIER_NATIVE = "native";
-    static final String MODIFIER_PRIVATE = "private";
-    static final String MODIFIER_PROTECTED = "protected";
-    static final String MODIFIER_PUBLIC = "public";
-    static final String MODIFIER_STATIC = "static";
-    static final String MODIFIER_SYNCHRONIZED = "synchronized";
-    static final String MODIFIER_TRANSIENT = "transient";
-    static final String MODIFIER_VOLATILE = "volatile";
-    static final String MODIFIER_VISIBILITY = "visibility";
+    private static final String MODIFIER_ABSTRACT = "abstract";
+    private static final String MODIFIER_FINAL = "final";
+    private static final String MODIFIER_NATIVE = "native";
+    private static final String MODIFIER_PRIVATE = "private";
+    private static final String MODIFIER_PROTECTED = "protected";
+    private static final String MODIFIER_PUBLIC = "public";
+    private static final String MODIFIER_STATIC = "static";
+    private static final String MODIFIER_SYNCHRONIZED = "synchronized";
+    private static final String MODIFIER_TRANSIENT = "transient";
+    private static final String MODIFIER_VOLATILE = "volatile";
+    private static final String MODIFIER_VISIBILITY = "visibility";
 
     static final String ATTRIBUTE_NAME = "name";
-    static final String ATTRIBUTE_VALUE = "value";
-    static final String ATTRIBUTE_EXTENDS = "extends";
+    private static final String ATTRIBUTE_VALUE = "value";
+    private static final String ATTRIBUTE_EXTENDS = "extends";
     static final String ATTRIBUTE_TYPE = "type";
-    static final String ATTRIBUTE_RETURN = "return";
+    private static final String ATTRIBUTE_RETURN = "return";
 
     /**
      * Load field information from xml to memory.
@@ -103,7 +103,7 @@
      * @return the new constructor
      */
     static JDiffConstructor loadConstructorInfo(
-                XmlPullParser parser, JDiffClassDescription currentClass) {
+            XmlPullParser parser, JDiffClassDescription currentClass) {
         String name = currentClass.getClassName();
         int modifier = jdiffModifierToReflectionFormat(name, parser);
         return new JDiffConstructor(name, modifier);
@@ -118,15 +118,9 @@
      * @return the new class description.
      */
     static JDiffClassDescription loadClassInfo(
-            XmlPullParser parser, boolean isInterface, String pkg,
-            ResultObserver resultObserver) {
+            XmlPullParser parser, boolean isInterface, String pkg) {
         String className = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-        JDiffClassDescription currentClass;
-        if (resultObserver != null) {
-            currentClass = new JDiffClassDescription(pkg, className, resultObserver);
-        } else {
-            currentClass = new JDiffClassDescription(pkg, className);
-        }
+        JDiffClassDescription currentClass = new JDiffClassDescription(pkg, className);
 
         currentClass.setModifier(jdiffModifierToReflectionFormat(className, parser));
         currentClass.setType(isInterface ? JDiffClassDescription.JDiffType.INTERFACE :
@@ -143,7 +137,7 @@
      * @param value modifier value
      * @return converted modifier value
      */
-    static int modifierDescriptionToReflectedType(String name, String key, String value) {
+    private static int modifierDescriptionToReflectedType(String name, String key, String value) {
         if (key.equals(MODIFIER_ABSTRACT)) {
             return value.equals("true") ? Modifier.ABSTRACT : 0;
         } else if (key.equals(MODIFIER_FINAL)) {
@@ -183,7 +177,7 @@
      * @param parser XML resource parser
      * @return converted modifier
      */
-    static int jdiffModifierToReflectionFormat(String name, XmlPullParser parser){
+    private static int jdiffModifierToReflectionFormat(String name, XmlPullParser parser){
         int modifier = 0;
         for (int i = 0;i < parser.getAttributeCount();i++) {
             modifier |= modifierDescriptionToReflectedType(name, parser.getAttributeName(i),
diff --git a/tests/signature/src/android/signature/cts/FailureType.java b/tests/signature/src/android/signature/cts/FailureType.java
index a701202..77820eb 100644
--- a/tests/signature/src/android/signature/cts/FailureType.java
+++ b/tests/signature/src/android/signature/cts/FailureType.java
@@ -13,5 +13,6 @@
     MISMATCH_INTERFACE_METHOD,
     MISMATCH_METHOD,
     MISMATCH_FIELD,
+    UNEXPECTED_CLASS,
     CAUGHT_EXCEPTION,
 }
diff --git a/tests/signature/src/android/signature/cts/IntentTest.java b/tests/signature/src/android/signature/cts/IntentTest.java
deleted file mode 100644
index 3d674ab..0000000
--- a/tests/signature/src/android/signature/cts/IntentTest.java
+++ /dev/null
@@ -1,289 +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 android.signature.cts;
-
-import static android.signature.cts.CurrentApi.CURRENT_API_FILE;
-import static android.signature.cts.CurrentApi.SYSTEM_CURRENT_API_FILE;
-import static android.signature.cts.CurrentApi.TAG_ROOT;
-import static android.signature.cts.CurrentApi.TAG_PACKAGE;
-import static android.signature.cts.CurrentApi.TAG_CLASS;
-import static android.signature.cts.CurrentApi.TAG_INTERFACE;
-import static android.signature.cts.CurrentApi.TAG_IMPLEMENTS;
-import static android.signature.cts.CurrentApi.TAG_CONSTRUCTOR;
-import static android.signature.cts.CurrentApi.TAG_METHOD;
-import static android.signature.cts.CurrentApi.TAG_PARAM;
-import static android.signature.cts.CurrentApi.TAG_EXCEPTION;
-import static android.signature.cts.CurrentApi.TAG_FIELD;
-
-import static android.signature.cts.CurrentApi.MODIFIER_ABSTRACT;
-import static android.signature.cts.CurrentApi.MODIFIER_FINAL;
-import static android.signature.cts.CurrentApi.MODIFIER_NATIVE;
-import static android.signature.cts.CurrentApi.MODIFIER_PRIVATE;
-import static android.signature.cts.CurrentApi.MODIFIER_PROTECTED;
-import static android.signature.cts.CurrentApi.MODIFIER_PUBLIC;
-import static android.signature.cts.CurrentApi.MODIFIER_STATIC;
-import static android.signature.cts.CurrentApi.MODIFIER_SYNCHRONIZED;
-import static android.signature.cts.CurrentApi.MODIFIER_TRANSIENT;
-import static android.signature.cts.CurrentApi.MODIFIER_VOLATILE;
-import static android.signature.cts.CurrentApi.MODIFIER_VISIBILITY;
-
-import static android.signature.cts.CurrentApi.ATTRIBUTE_NAME;
-import static android.signature.cts.CurrentApi.ATTRIBUTE_EXTENDS;
-import static android.signature.cts.CurrentApi.ATTRIBUTE_TYPE;
-import static android.signature.cts.CurrentApi.ATTRIBUTE_RETURN;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.signature.cts.JDiffClassDescription.JDiffConstructor;
-import android.signature.cts.JDiffClassDescription.JDiffField;
-import android.signature.cts.JDiffClassDescription.JDiffMethod;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
-
-import com.android.compatibility.common.util.DynamicConfigDeviceSide;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.io.File;
-import java.io.FileInputStream;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.junit.Assert;
-import org.junit.runner.RunWith;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-/**
- * Validate that the android intents used by APKs on this device are part of the
- * platform.
- */
-@RunWith(AndroidJUnit4.class)
-public class IntentTest {
-    private static final String TAG = IntentTest.class.getSimpleName();
-
-    private static final File SIGNATURE_TEST_PACKGES =
-            new File("/data/local/tmp/signature-test-packages");
-    private static final String ANDROID_INTENT_PREFIX = "android.intent.action";
-    private static final String ACTION_LINE_PREFIX = "          Action: ";
-    private static final String MODULE_NAME = "CtsSignatureTestCases";
-
-    private PackageManager mPackageManager;
-    private Set<String> intentWhitelist;
-
-    @Before
-    public void setupPackageManager() throws Exception {
-      mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
-      intentWhitelist = getIntentWhitelist();
-    }
-
-    @Test
-    public void shouldNotFindUnexpectedIntents() throws Exception {
-        Set<String> platformIntents = lookupPlatformIntents();
-        platformIntents.addAll(intentWhitelist);
-
-        Set<String> allInvalidIntents = new HashSet<>();
-
-        Set<String> errors = new HashSet<>();
-        List<ApplicationInfo> packages =
-            mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA);
-        for (ApplicationInfo appInfo : packages) {
-            if (!isSystemApp(appInfo) && !isUpdatedSystemApp(appInfo)) {
-                // Only examine system apps
-                continue;
-            }
-            Set<String> invalidIntents = new HashSet<>();
-            Set<String> activeIntents = lookupActiveIntents(appInfo.packageName);
-
-            for (String activeIntent : activeIntents) {
-              String intent = activeIntent.trim();
-              if (!platformIntents.contains(intent) &&
-                    intent.startsWith(ANDROID_INTENT_PREFIX)) {
-                  invalidIntents.add(activeIntent);
-                  allInvalidIntents.add(activeIntent);
-              }
-            }
-
-            String error = String.format("Package: %s Invalid Intent: %s",
-                  appInfo.packageName, invalidIntents);
-            if (!invalidIntents.isEmpty()) {
-                errors.add(error);
-            }
-        }
-
-        // Log the whitelist line to make it easy to update.
-        for (String intent : allInvalidIntents) {
-           Log.d(TAG, String.format("whitelist.add(\"%s\");", intent));
-        }
-
-        Assert.assertTrue(errors.toString(), errors.isEmpty());
-    }
-
-    private Set<String> lookupPlatformIntents() {
-        try {
-            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
-
-            Set<String> intents = new HashSet<>();
-            XmlPullParser parser = factory.newPullParser();
-            parser.setInput(new FileInputStream(new File(CURRENT_API_FILE)), null);
-            intents.addAll(parse(parser));
-
-            parser = factory.newPullParser();
-            parser.setInput(new FileInputStream(new File(SYSTEM_CURRENT_API_FILE)), null);
-            intents.addAll(parse(parser));
-            return intents;
-        } catch (XmlPullParserException | IOException e) {
-            throw new RuntimeException("failed to parse", e);
-        }
-    }
-
-    private static Set<String> parse(XmlPullParser parser)
-            throws XmlPullParserException, IOException {
-        JDiffClassDescription currentClass = null;
-        String currentPackage = "";
-        JDiffMethod currentMethod = null;
-
-        Set<String> androidIntents = new HashSet<>();
-        Set<String> keyTagSet = new HashSet<String>();
-        keyTagSet.addAll(Arrays.asList(new String[] {
-                TAG_PACKAGE, TAG_CLASS, TAG_INTERFACE, TAG_IMPLEMENTS, TAG_CONSTRUCTOR,
-                TAG_METHOD, TAG_PARAM, TAG_EXCEPTION, TAG_FIELD }));
-
-        int type;
-        while ((type=parser.next()) != XmlPullParser.START_TAG
-                   && type != XmlPullParser.END_DOCUMENT) { }
-
-        if (type != XmlPullParser.START_TAG) {
-            throw new XmlPullParserException("No start tag found");
-        }
-
-        if (!parser.getName().equals(TAG_ROOT)) {
-            throw new XmlPullParserException(
-                  "Unexpected start tag: found " + parser.getName() + ", expected " + TAG_ROOT);
-        }
-
-        while (true) {
-            type = XmlPullParser.START_DOCUMENT;
-            while ((type=parser.next()) != XmlPullParser.START_TAG
-                       && type != XmlPullParser.END_DOCUMENT
-                       && type != XmlPullParser.END_TAG) {
-            }
-
-            if (type == XmlPullParser.END_TAG) {
-                if (TAG_PACKAGE.equals(parser.getName())) {
-                    currentPackage = "";
-                }
-                continue;
-            }
-
-            if (type == XmlPullParser.END_DOCUMENT) {
-                break;
-            }
-
-            String tagname = parser.getName();
-            if (!keyTagSet.contains(tagname)) {
-                continue;
-            }
-
-            if (type == XmlPullParser.START_TAG && tagname.equals(TAG_PACKAGE)) {
-                currentPackage = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-            } else if (tagname.equals(TAG_CLASS)) {
-                currentClass = CurrentApi.loadClassInfo(
-                      parser, false, currentPackage, null /*resultObserver*/);
-            } else if (tagname.equals(TAG_INTERFACE)) {
-                currentClass = CurrentApi.loadClassInfo(
-                      parser, true, currentPackage, null /*resultObserver*/);
-            } else if (tagname.equals(TAG_FIELD)) {
-                JDiffField field =
-                    CurrentApi.loadFieldInfo(currentClass.getClassName(), parser);
-                currentClass.addField(field);
-            }
-
-            if (currentClass != null) {
-                for (JDiffField diffField : currentClass.getFieldList()) {
-                    String fieldValue = diffField.getValueString();
-                    if (fieldValue != null) {
-                        fieldValue = fieldValue.replace("\"", "");
-                        if (fieldValue.startsWith(ANDROID_INTENT_PREFIX)) {
-                            androidIntents.add(fieldValue);
-                        }
-                    }
-                }
-            }
-        }
-
-        return androidIntents;
-    }
-
-    private static boolean isSystemApp(ApplicationInfo applicationInfo) {
-        return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-    }
-
-    private static boolean isUpdatedSystemApp(ApplicationInfo applicationInfo) {
-        return (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
-    }
-
-    private static Set<String> lookupActiveIntents(String packageName) {
-        HashSet<String> activeIntents = new HashSet<>();
-        File dumpsysPackage = new File(SIGNATURE_TEST_PACKGES, packageName + ".txt");
-        if (!dumpsysPackage.exists() || dumpsysPackage.length() == 0) {
-          throw new RuntimeException("Missing package info: " + dumpsysPackage.getAbsolutePath());
-        }
-        try (
-            BufferedReader in = new BufferedReader(
-                  new InputStreamReader(new FileInputStream(dumpsysPackage)))) {
-            String line;
-            while ((line = in.readLine()) != null) {
-                if (line.startsWith(ACTION_LINE_PREFIX)) {
-                    String intent = line.substring(
-                          ACTION_LINE_PREFIX.length(), line.length() - 1);
-                    activeIntents.add(intent.replace("\"", ""));
-                }
-            }
-            return activeIntents;
-        } catch (Exception e) {
-          throw new RuntimeException("While retrieving dumpsys", e);
-        }
-    }
-
-    private static Set<String> getIntentWhitelist() throws Exception {
-        Set<String> whitelist = new HashSet<>();
-
-        DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(MODULE_NAME);
-        List<String> intentWhitelist = dcds.getValues("intent_whitelist");
-
-        // Log the whitelist Intent
-        for (String intent : intentWhitelist) {
-           Log.d(TAG, String.format("whitelist add: %s", intent));
-           whitelist.add(intent);
-        }
-
-        return whitelist;
-    }
-}
diff --git a/tests/signature/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
index 2d13ed2..df91ddb 100644
--- a/tests/signature/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
@@ -16,86 +16,37 @@
 
 package android.signature.cts;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
 
 /**
  * Represents class descriptions loaded from a jdiff xml file.  Used
  * for CTS SignatureTests.
  */
 public class JDiffClassDescription {
-    /** Indicates that the class is an annotation. */
-    private static final int CLASS_MODIFIER_ANNOTATION = 0x00002000;
-    /** Indicates that the class is an enum. */
-    private static final int CLASS_MODIFIER_ENUM       = 0x00004000;
-
-    /** Indicates that the method is a bridge method. */
-    private static final int METHOD_MODIFIER_BRIDGE    = 0x00000040;
-    /** Indicates that the method is takes a variable number of arguments. */
-    private static final int METHOD_MODIFIER_VAR_ARGS  = 0x00000080;
-    /** Indicates that the method is a synthetic method. */
-    private static final int METHOD_MODIFIER_SYNTHETIC = 0x00001000;
-
-    private static final Set<String> HIDDEN_INTERFACE_WHITELIST = new HashSet<>();
-    static {
-        // Interfaces that define @hide methods will by definition contain
-        // methods that do not appear in current.txt. Interfaces added to this
-        // list are probably not meant to be implemented in an application.
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract boolean android.companion.DeviceFilter.matches(D)");
-        HIDDEN_INTERFACE_WHITELIST.add("public static <D> boolean android.companion.DeviceFilter.matches(android.companion.DeviceFilter<D>,D)");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract java.lang.String android.companion.DeviceFilter.getDeviceDisplayName(D)");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract int android.companion.DeviceFilter.getMediumType()");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.nfc.tech.TagTechnology.reconnect() throws java.io.IOException");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.os.IBinder.shellCommand(java.io.FileDescriptor,java.io.FileDescriptor,java.io.FileDescriptor,java.lang.String[],android.os.ShellCallback,android.os.ResultReceiver) throws android.os.RemoteException");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract int android.text.ParcelableSpan.getSpanTypeIdInternal()");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.text.ParcelableSpan.writeToParcelInternal(android.os.Parcel,int)");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract void android.view.WindowManager.requestAppKeyboardShortcuts(android.view.WindowManager$KeyboardShortcutsReceiver,int)");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract boolean javax.microedition.khronos.egl.EGL10.eglReleaseThread()");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract void org.w3c.dom.ls.LSSerializer.setFilter(org.w3c.dom.ls.LSSerializerFilter)");
-        HIDDEN_INTERFACE_WHITELIST.add("public abstract org.w3c.dom.ls.LSSerializerFilter org.w3c.dom.ls.LSSerializer.getFilter()");
-    }
 
     public enum JDiffType {
         INTERFACE, CLASS
     }
 
-    @SuppressWarnings("unchecked")
-    private Class<?> mClass;
-    // A map of field name to field of the fields contained in {@code mClass}
-    private Map<String, Field> mClassFieldMap;
-
-    private String mPackageName;
-    private String mShortClassName;
+    private final String mPackageName;
+    private final String mShortClassName;
 
     /**
      * Package name + short class name
      */
-    private String mAbsoluteClassName;
+    private final String mAbsoluteClassName;
 
     private int mModifier;
 
     private String mExtendedClass;
-    private List<String> implInterfaces = new ArrayList<String>();
-    private List<JDiffField> jDiffFields = new ArrayList<JDiffField>();
-    private List<JDiffMethod> jDiffMethods = new ArrayList<JDiffMethod>();
-    private List<JDiffConstructor> jDiffConstructors = new ArrayList<JDiffConstructor>();
+    private List<String> implInterfaces = new ArrayList<>();
+    private List<JDiffField> jDiffFields = new ArrayList<>();
+    private List<JDiffMethod> jDiffMethods = new ArrayList<>();
+    private List<JDiffConstructor> jDiffConstructors = new ArrayList<>();
 
-    private ResultObserver mResultObserver;
     private JDiffType mClassType;
 
     /**
@@ -105,26 +56,46 @@
      * @param className the name of the class.
      */
     public JDiffClassDescription(String pkg, String className) {
-        this(pkg, className, new ResultObserver() {
-            @Override
-            public void notifyFailure(FailureType type, String name, String errorMessage) {
-                // This is a null result observer that doesn't do anything.
-            }
-        });
-    }
-
-    /**
-     * Creates a new JDiffClassDescription with the specified results
-     * observer.
-     *
-     * @param pkg the java package this class belongs in.
-     * @param className the name of the class.
-     * @param resultObserver the resultObserver to get results with.
-     */
-    public JDiffClassDescription(String pkg, String className, ResultObserver resultObserver) {
         mPackageName = pkg;
         mShortClassName = className;
-        mResultObserver = resultObserver;
+        mAbsoluteClassName = mPackageName + "." + mShortClassName;
+    }
+
+
+    String getPackageName() {
+        return mPackageName;
+    }
+
+    String getShortClassName() {
+        return mShortClassName;
+    }
+
+    int getModifier() {
+        return mModifier;
+    }
+
+    String getExtendedClass() {
+        return mExtendedClass;
+    }
+
+    List<String> getImplInterfaces() {
+        return implInterfaces;
+    }
+
+    List<JDiffField> getFields() {
+        return jDiffFields;
+    }
+
+    List<JDiffMethod> getMethods() {
+        return jDiffMethods;
+    }
+
+    List<JDiffConstructor> getConstructors() {
+        return jDiffConstructors;
+    }
+
+    JDiffType getClassType() {
+        return mClassType;
     }
 
     /**
@@ -132,7 +103,7 @@
      *
      * @param iname name of interface
      */
-    public void addImplInterface(String iname) {
+    void addImplInterface(String iname) {
         implInterfaces.add(iname);
     }
 
@@ -177,83 +148,50 @@
     }
 
     static String convertModifersToModifierString(int modifiers) {
-        StringBuffer sb = new StringBuffer();
-        boolean isFirst = true;
+        StringBuilder sb = new StringBuilder();
+        String separator = "";
 
         // order taken from Java Language Spec, sections 8.1.1, 8.3.1, and 8.4.3
         if ((modifiers & Modifier.ABSTRACT) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("abstract");
+            sb.append(separator).append("abstract");
+            separator = " ";
         }
         if ((modifiers & Modifier.STATIC) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("static");
+            sb.append(separator).append("static");
+            separator = " ";
         }
         if ((modifiers & Modifier.FINAL) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("final");
+            sb.append(separator).append("final");
+            separator = " ";
         }
         if ((modifiers & Modifier.TRANSIENT) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("transient");
+            sb.append(separator).append("transient");
+            separator = " ";
         }
         if ((modifiers & Modifier.VOLATILE) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("volatile");
+            sb.append(separator).append("volatile");
+            separator = " ";
         }
         if ((modifiers & Modifier.SYNCHRONIZED) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("synchronized");
+            sb.append(separator).append("synchronized");
+            separator = " ";
         }
         if ((modifiers & Modifier.NATIVE) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("native");
+            sb.append(separator).append("native");
+            separator = " ";
         }
         if ((modifiers & Modifier.STRICT) != 0) {
-            if (isFirst) {
-                isFirst = false;
-            } else {
-                sb.append(" ");
-            }
-            sb.append("strictfp");
+            sb.append(separator).append("strictfp");
         }
 
         return sb.toString();
     }
 
-    public abstract static class JDiffElement {
+    abstract static class JDiffElement {
         final String mName;
         int mModifier;
 
-        public JDiffElement(String name, int modifier) {
+        JDiffElement(String name, int modifier) {
             mName = name;
             mModifier = modifier;
         }
@@ -263,7 +201,7 @@
      * Represents a  field.
      */
     public static final class JDiffField extends JDiffElement {
-        private String mFieldType;
+        String mFieldType;
         private String mFieldValue;
 
         public JDiffField(String name, String fieldType, int modifier, String value) {
@@ -286,12 +224,12 @@
          * @param className The specified class name.
          * @return A readable string to represent this field along with the class name.
          */
-        public String toReadableString(String className) {
+        String toReadableString(String className) {
             return className + "#" + mName + "(" + mFieldType + ")";
         }
 
         public String toSignatureString() {
-            StringBuffer sb = new StringBuffer();
+            StringBuilder sb = new StringBuilder();
 
             // access level
             String accesLevel = convertModifiersToAccessLevel(mModifier);
@@ -316,9 +254,9 @@
      * Represents a method.
      */
     public static class JDiffMethod extends JDiffElement {
-        protected String mReturnType;
-        protected ArrayList<String> mParamList;
-        protected ArrayList<String> mExceptionList;
+        String mReturnType;
+        ArrayList<String> mParamList;
+        ArrayList<String> mExceptionList;
 
         public JDiffMethod(String name, int modifier, String returnType) {
             super(name, modifier);
@@ -329,8 +267,8 @@
                 mReturnType = scrubJdiffParamType(returnType);
             }
 
-            mParamList = new ArrayList<String>();
-            mExceptionList = new ArrayList<String>();
+            mParamList = new ArrayList<>();
+            mExceptionList = new ArrayList<>();
         }
 
         /**
@@ -357,7 +295,7 @@
          * @param className The specified class name.
          * @return A readable string to represent this method along with the class name.
          */
-        public String toReadableString(String className) {
+        String toReadableString(String className) {
             return className + "#" + mName + "(" + convertParamList(mParamList) + ")";
         }
 
@@ -369,11 +307,11 @@
          */
         private static String convertParamList(final ArrayList<String> params) {
 
-            StringBuffer paramList = new StringBuffer();
+            StringBuilder paramList = new StringBuilder();
 
             if (params != null) {
                 for (String str : params) {
-                    paramList.append(str + ", ");
+                    paramList.append(str).append(", ");
                 }
                 if (params.size() > 0) {
                     paramList.delete(paramList.length() - 2, paramList.length());
@@ -384,7 +322,7 @@
         }
 
         public String toSignatureString() {
-            StringBuffer sb = new StringBuffer();
+            StringBuilder sb = new StringBuilder();
 
             // access level
             String accesLevel = convertModifiersToAccessLevel(mModifier);
@@ -444,14 +382,6 @@
             super(name, modifier, null);
         }
 
-        public JDiffConstructor(String name, String[] param, int modifier) {
-            super(name, modifier, null);
-
-            for (int i = 0; i < param.length; i++) {
-                addParam(param[i]);
-            }
-        }
-
         /**
          * Gets the return type.
          *
@@ -465,551 +395,6 @@
     }
 
     /**
-     * Checks test class's name, modifier, fields, constructors, and
-     * methods.
-     */
-    public void checkSignatureCompliance() {
-        checkClassCompliance();
-        if (mClass != null) {
-            mClassFieldMap = buildFieldMap(mClass);
-            checkFieldsCompliance();
-            checkConstructorCompliance();
-            checkMethodCompliance();
-        } else {
-            mClassFieldMap = null;
-        }
-    }
-
-    /**
-     * Checks to ensure that the modifiers value for two methods are
-     * compatible.
-     *
-     * Allowable differences are:
-     *   - synchronized is allowed to be removed from an apiMethod
-     *     that has it
-     *   - the native modified is ignored
-     *
-     * @param apiMethod the method read from the api file.
-     * @param reflectedMethod the method found via reflections.
-     */
-    private boolean areMethodsModifiedCompatible(JDiffMethod apiMethod ,
-            Method reflectedMethod) {
-
-        // If the apiMethod isn't synchronized
-        if (((apiMethod.mModifier & Modifier.SYNCHRONIZED) == 0) &&
-                // but the reflected method is
-                ((reflectedMethod.getModifiers() & Modifier.SYNCHRONIZED) != 0)) {
-            // that is a problem
-            return false;
-        }
-
-        // Mask off NATIVE since it is a don't care.  Also mask off
-        // SYNCHRONIZED since we've already handled that check.
-        int ignoredMods = (Modifier.NATIVE | Modifier.SYNCHRONIZED | Modifier.STRICT);
-        int mod1 = reflectedMethod.getModifiers() & ~ignoredMods;
-        int mod2 = apiMethod.mModifier & ~ignoredMods;
-
-        // We can ignore FINAL for classes
-        if ((mModifier & Modifier.FINAL) != 0) {
-            mod1 &= ~Modifier.FINAL;
-            mod2 &= ~Modifier.FINAL;
-        }
-
-        return mod1 == mod2;
-    }
-
-    /**
-     * Checks that the method found through reflection matches the
-     * specification from the API xml file.
-     */
-    private void checkMethodCompliance() {
-        for (JDiffMethod method : jDiffMethods) {
-            try {
-
-                Method m = findMatchingMethod(method);
-                if (m == null) {
-                    mResultObserver.notifyFailure(FailureType.MISSING_METHOD,
-                            method.toReadableString(mAbsoluteClassName),
-                            "No method with correct signature found:" +
-                            method.toSignatureString());
-                } else {
-                    if (m.isVarArgs()) {
-                        method.mModifier |= METHOD_MODIFIER_VAR_ARGS;
-                    }
-                    if (m.isBridge()) {
-                        method.mModifier |= METHOD_MODIFIER_BRIDGE;
-                    }
-                    if (m.isSynthetic()) {
-                        method.mModifier |= METHOD_MODIFIER_SYNTHETIC;
-                    }
-
-                    // FIXME: A workaround to fix the final mismatch on enumeration
-                    if (mClass.isEnum() && method.mName.equals("values")) {
-                        return;
-                    }
-
-                    if (!areMethodsModifiedCompatible(method, m)) {
-                        mResultObserver.notifyFailure(FailureType.MISMATCH_METHOD,
-                                method.toReadableString(mAbsoluteClassName),
-                                "Non-compatible method found when looking for " +
-                                method.toSignatureString());
-                    }
-                }
-            } catch (Exception e) {
-                loge("Got exception when checking method compliance", e);
-                mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION,
-                        method.toReadableString(mAbsoluteClassName),
-                "Exception!");
-            }
-        }
-    }
-
-    /**
-     * Checks if the two types of methods are the same.
-     *
-     * @param jDiffMethod the jDiffMethod to compare
-     * @param method the reflected method to compare
-     * @return true, if both methods are the same
-     */
-    private boolean matches(JDiffMethod jDiffMethod, Method reflectedMethod) {
-        // If the method names aren't equal, the methods can't match.
-        if (!jDiffMethod.mName.equals(reflectedMethod.getName())) {
-            return false;
-        }
-        String jdiffReturnType = jDiffMethod.mReturnType;
-        String reflectionReturnType = typeToString(reflectedMethod.getGenericReturnType());
-        List<String> jdiffParamList = jDiffMethod.mParamList;
-
-        // Next, compare the return types of the two methods.  If
-        // they aren't equal, the methods can't match.
-        if (!jdiffReturnType.equals(reflectionReturnType)) {
-            return false;
-        }
-
-        Type[] params = reflectedMethod.getGenericParameterTypes();
-
-        // Next, check the method parameters.  If they have different
-        // parameter lengths, the two methods can't match.
-        if (jdiffParamList.size() != params.length) {
-            return false;
-        }
-
-        boolean piecewiseParamsMatch = true;
-
-        // Compare method parameters piecewise and return true if they all match.
-        for (int i = 0; i < jdiffParamList.size(); i++) {
-            piecewiseParamsMatch &= compareParam(jdiffParamList.get(i), params[i]);
-        }
-        if (piecewiseParamsMatch) {
-            return true;
-        }
-
-        /** NOTE: There are cases where piecewise method parameter checking
-         * fails even though the strings are equal, so compare entire strings
-         * against each other. This is not done by default to avoid a
-         * TransactionTooLargeException.
-         * Additionally, this can fail anyway due to extra
-         * information dug up by reflection.
-         *
-         * TODO: fix parameter equality checking and reflection matching
-         * See https://b.corp.google.com/issues/27726349
-         */
-
-        StringBuilder reflectedMethodParams = new StringBuilder("");
-        StringBuilder jdiffMethodParams = new StringBuilder("");
-
-        for (int i = 0; i < jdiffParamList.size(); i++) {
-            jdiffMethodParams.append(jdiffParamList.get(i));
-            reflectedMethodParams.append(params[i]);
-        }
-
-        String jDiffFName = jdiffMethodParams.toString();
-        String refName = reflectedMethodParams.toString();
-
-        return jDiffFName.equals(refName);
-    }
-
-    /**
-     * Finds the reflected method specified by the method description.
-     *
-     * @param method description of the method to find
-     * @return the reflected method, or null if not found.
-     */
-    @SuppressWarnings("unchecked")
-    private Method findMatchingMethod(JDiffMethod method) {
-        Method[] methods = mClass.getDeclaredMethods();
-
-        for (Method m : methods) {
-            if (matches(method, m)) {
-                return m;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Compares the parameter from the API and the parameter from
-     * reflection.
-     *
-     * @param jdiffParam param parsed from the API xml file.
-     * @param reflectionParamType param gotten from the Java reflection.
-     * @return True if the two params match, otherwise return false.
-     */
-    private static boolean compareParam(String jdiffParam, Type reflectionParamType) {
-        if (jdiffParam == null) {
-            return false;
-        }
-
-        String reflectionParam = typeToString(reflectionParamType);
-        // Most things aren't varargs, so just do a simple compare
-        // first.
-        if (jdiffParam.equals(reflectionParam)) {
-            return true;
-        }
-
-        // Check for varargs.  jdiff reports varargs as ..., while
-        // reflection reports them as []
-        int jdiffParamEndOffset = jdiffParam.indexOf("...");
-        int reflectionParamEndOffset = reflectionParam.indexOf("[]");
-        if (jdiffParamEndOffset != -1 && reflectionParamEndOffset != -1) {
-            jdiffParam = jdiffParam.substring(0, jdiffParamEndOffset);
-            reflectionParam = reflectionParam.substring(0, reflectionParamEndOffset);
-            return jdiffParam.equals(reflectionParam);
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks whether the constructor parsed from API xml file and
-     * Java reflection are compliant.
-     */
-    @SuppressWarnings("unchecked")
-    private void checkConstructorCompliance() {
-        for (JDiffConstructor con : jDiffConstructors) {
-            try {
-                Constructor<?> c = findMatchingConstructor(con);
-                if (c == null) {
-                    mResultObserver.notifyFailure(FailureType.MISSING_METHOD,
-                            con.toReadableString(mAbsoluteClassName),
-                            "No method with correct signature found:" +
-                            con.toSignatureString());
-                } else {
-                    if (c.isVarArgs()) {// some method's parameter are variable args
-                        con.mModifier |= METHOD_MODIFIER_VAR_ARGS;
-                    }
-                    if (c.getModifiers() != con.mModifier) {
-                        mResultObserver.notifyFailure(
-                                FailureType.MISMATCH_METHOD,
-                                con.toReadableString(mAbsoluteClassName),
-                                "Non-compatible method found when looking for " +
-                                con.toSignatureString());
-                    }
-                }
-            } catch (Exception e) {
-                loge("Got exception when checking constructor compliance", e);
-                mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION,
-                        con.toReadableString(mAbsoluteClassName),
-                "Exception!");
-            }
-        }
-    }
-
-    /**
-     * Searches available constructor.
-     *
-     * @param jdiffDes constructor description to find.
-     * @return reflected constructor, or null if not found.
-     */
-    @SuppressWarnings("unchecked")
-    private Constructor<?> findMatchingConstructor(JDiffConstructor jdiffDes) {
-        for (Constructor<?> c : mClass.getDeclaredConstructors()) {
-            Type[] params = c.getGenericParameterTypes();
-            boolean isStaticClass = ((mClass.getModifiers() & Modifier.STATIC) != 0);
-
-            int startParamOffset = 0;
-            int numberOfParams = params.length;
-
-            // non-static inner class -> skip implicit parent pointer
-            // as first arg
-            if (mClass.isMemberClass() && !isStaticClass && params.length >= 1) {
-                startParamOffset = 1;
-                --numberOfParams;
-            }
-
-            ArrayList<String> jdiffParamList = jdiffDes.mParamList;
-            if (jdiffParamList.size() == numberOfParams) {
-                boolean isFound = true;
-                // i counts jdiff params, j counts reflected params
-                int i = 0;
-                int j = startParamOffset;
-                while (i < jdiffParamList.size()) {
-                    if (!compareParam(jdiffParamList.get(i), params[j])) {
-                        isFound = false;
-                        break;
-                    }
-                    ++i;
-                    ++j;
-                }
-                if (isFound) {
-                    return c;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Checks all fields in test class for compliance with the API
-     * xml.
-     */
-    @SuppressWarnings("unchecked")
-    private void checkFieldsCompliance() {
-        for (JDiffField field : jDiffFields) {
-            try {
-                Field f = findMatchingField(field);
-                if (f == null) {
-                    mResultObserver.notifyFailure(FailureType.MISSING_FIELD,
-                            field.toReadableString(mAbsoluteClassName),
-                            "No field with correct signature found:" +
-                            field.toSignatureString());
-                } else if (f.getModifiers() != field.mModifier) {
-                    mResultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
-                            field.toReadableString(mAbsoluteClassName),
-                            "Non-compatible field modifiers found when looking for " +
-                            field.toSignatureString());
-                } else if (!checkFieldValueCompliance(field, f)) {
-                    mResultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
-                            field.toReadableString(mAbsoluteClassName),
-                            "Incorrect field value found when looking for " +
-                            field.toSignatureString());
-                }else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
-                    // type name does not match, but this might be a generic
-                    String genericTypeName = null;
-                    Type type = f.getGenericType();
-                    if (type != null) {
-                        genericTypeName = type instanceof Class ? ((Class) type).getName() :
-                            type.toString().replace('$', '.');
-                    }
-                    if (genericTypeName == null || !genericTypeName.equals(field.mFieldType)) {
-                        mResultObserver.notifyFailure(
-                                FailureType.MISMATCH_FIELD,
-                                field.toReadableString(mAbsoluteClassName),
-                                "Non-compatible field type found when looking for " +
-                                field.toSignatureString());
-                    }
-                }
-
-            } catch (Exception e) {
-                loge("Got exception when checking field compliance", e);
-                mResultObserver.notifyFailure(
-                        FailureType.CAUGHT_EXCEPTION,
-                        field.toReadableString(mAbsoluteClassName),
-                        "Exception!");
-            }
-        }
-    }
-
-    /**
-     * Checks whether the field values are compatible.
-     *
-     * @param apiField The field as defined by the platform API.
-     * @param deviceField The field as defined by the device under test.
-     */
-    private boolean checkFieldValueCompliance(JDiffField apiField, Field deviceField)
-            throws IllegalAccessException {
-        if ((apiField.mModifier & Modifier.FINAL) == 0 ||
-                (apiField.mModifier & Modifier.STATIC) == 0) {
-            // Only final static fields can have fixed values.
-            return true;
-        }
-        if (apiField.getValueString() == null) {
-            // If we don't define a constant value for it, then it can be anything.
-            return true;
-        }
-        // Some fields may be protected or package-private
-        deviceField.setAccessible(true);
-        switch(apiField.mFieldType) {
-            case "byte":
-                return Objects.equals(apiField.getValueString(),
-                        Byte.toString(deviceField.getByte(null)));
-            case "char":
-                return Objects.equals(apiField.getValueString(),
-                        Integer.toString(deviceField.getChar(null)));
-            case "short":
-                return Objects.equals(apiField.getValueString(),
-                        Short.toString(deviceField.getShort(null)));
-            case "int":
-                return Objects.equals(apiField.getValueString(),
-                        Integer.toString(deviceField.getInt(null)));
-            case "long":
-                return Objects.equals(apiField.getValueString(),
-                        Long.toString(deviceField.getLong(null)) + "L");
-            case "float":
-                return Objects.equals(apiField.getValueString(),
-                        canonicalizeFloatingPoint(
-                            Float.toString(deviceField.getFloat(null)), "f"));
-            case "double":
-                return Objects.equals(apiField.getValueString(),
-                        canonicalizeFloatingPoint(
-                            Double.toString(deviceField.getDouble(null)), ""));
-            case "boolean":
-                return Objects.equals(apiField.getValueString(),
-                        Boolean.toString(deviceField.getBoolean(null)));
-            case "java.lang.String":
-                String value = apiField.getValueString();
-                // Remove the quotes the value string is wrapped in
-                value = unescapeFieldStringValue(value.substring(1, value.length() - 1));
-                return Objects.equals(value, deviceField.get(null));
-            default:
-                return true;
-        }
-    }
-
-    /**
-     * Canonicalize the string representation of floating point numbers.
-     *
-     * This needs to be kept in sync with the doclava canonicalization.
-     */
-    private static final String canonicalizeFloatingPoint(String val, String suffix) {
-        if (val.equals("Infinity")) {
-            return "(1.0" + suffix + "/0.0" + suffix + ")";
-        } else if (val.equals("-Infinity")) {
-            return "(-1.0" + suffix + "/0.0" + suffix + ")";
-        } else if (val.equals("NaN")) {
-            return "(0.0" + suffix + "/0.0" + suffix + ")";
-        }
-
-        String str = val.toString();
-        if (str.indexOf('E') != -1) {
-            return str + suffix;
-        }
-
-        // 1.0 is the only case where a trailing "0" is allowed.
-        // 1.00 is canonicalized as 1.0.
-        int i = str.length() - 1;
-        int d = str.indexOf('.');
-        while (i >= d + 2 && str.charAt(i) == '0') {
-            str = str.substring(0, i--);
-        }
-        return str + suffix;
-    }
-
-
-    // This unescapes the string format used by doclava and so needs to be kept in sync with any
-    // changes made to that format.
-    private static String unescapeFieldStringValue(String str) {
-        final int N = str.length();
-
-        // If there's no special encoding strings in the string then just return it.
-        if (str.indexOf('\\') == -1) {
-            return str;
-        }
-
-        final StringBuilder buf = new StringBuilder(str.length());
-        char escaped = 0;
-        final int START = 0;
-        final int CHAR1 = 1;
-        final int CHAR2 = 2;
-        final int CHAR3 = 3;
-        final int CHAR4 = 4;
-        final int ESCAPE = 5;
-        int state = START;
-
-        for (int i=0; i<N; i++) {
-            final char c = str.charAt(i);
-            switch (state) {
-                case START:
-                    if (c == '\\') {
-                        state = ESCAPE;
-                    } else {
-                        buf.append(c);
-                    }
-                    break;
-                case ESCAPE:
-                    switch (c) {
-                        case '\\':
-                            buf.append('\\');
-                            state = START;
-                            break;
-                        case 't':
-                            buf.append('\t');
-                            state = START;
-                            break;
-                        case 'b':
-                            buf.append('\b');
-                            state = START;
-                            break;
-                        case 'r':
-                            buf.append('\r');
-                            state = START;
-                            break;
-                        case 'n':
-                            buf.append('\n');
-                            state = START;
-                            break;
-                        case 'f':
-                            buf.append('\f');
-                            state = START;
-                            break;
-                        case '\'':
-                            buf.append('\'');
-                            state = START;
-                            break;
-                        case '\"':
-                            buf.append('\"');
-                            state = START;
-                            break;
-                        case 'u':
-                            state = CHAR1;
-                            escaped = 0;
-                            break;
-                    }
-                    break;
-                case CHAR1:
-                case CHAR2:
-                case CHAR3:
-                case CHAR4:
-                    escaped <<= 4;
-                    if (c >= '0' && c <= '9') {
-                        escaped |= c - '0';
-                    } else if (c >= 'a' && c <= 'f') {
-                        escaped |= 10 + (c - 'a');
-                    } else if (c >= 'A' && c <= 'F') {
-                        escaped |= 10 + (c - 'A');
-                    } else {
-                        throw new RuntimeException(
-                                "bad escape sequence: '" + c + "' at pos " + i + " in: \""
-                                + str + "\"");
-                    }
-                    if (state == CHAR4) {
-                        buf.append(escaped);
-                        state = START;
-                    } else {
-                        state++;
-                    }
-                    break;
-            }
-        }
-        if (state != START) {
-            throw new RuntimeException("unfinished escape sequence: " + str);
-        }
-        return buf.toString();
-    }
-
-
-    /**
-     * Finds the reflected field specified by the field description.
-     *
-     * @param field the field description to find
-     * @return the reflected field, or null if not found.
-     */
-    private Field findMatchingField(JDiffField field) {
-        return mClassFieldMap.get(field.mName);
-    }
-
-    /**
      * Gets the list of fields found within this class.
      *
      * @return the list of fields.
@@ -1019,217 +404,12 @@
     }
 
     /**
-     * Checks if the class under test has compliant modifiers compared to the API.
-     *
-     * @return true if modifiers are compliant.
-     */
-    private boolean checkClassModifiersCompliance() {
-        int reflectionModifier = mClass.getModifiers();
-        int apiModifier = mModifier;
-
-        // If the api class isn't abstract
-        if (((apiModifier & Modifier.ABSTRACT) == 0) &&
-                // but the reflected class is
-                ((reflectionModifier & Modifier.ABSTRACT) != 0) &&
-                // and it isn't an enum
-                !isEnumType()) {
-            // that is a problem
-            return false;
-        }
-        // ABSTRACT check passed, so mask off ABSTRACT
-        reflectionModifier &= ~Modifier.ABSTRACT;
-        apiModifier &= ~Modifier.ABSTRACT;
-
-        if (isAnnotation()) {
-            reflectionModifier &= ~CLASS_MODIFIER_ANNOTATION;
-        }
-        if (mClass.isInterface()) {
-            reflectionModifier &= ~(Modifier.INTERFACE);
-        }
-        if (isEnumType() && mClass.isEnum()) {
-            reflectionModifier &= ~CLASS_MODIFIER_ENUM;
-        }
-
-        return ((reflectionModifier == apiModifier) &&
-                (isEnumType() == mClass.isEnum()));
-    }
-
-    /**
-     * Checks if the class under test is compliant with regards to
-     * annnotations when compared to the API.
-     *
-     * @return true if the class is compliant
-     */
-    private boolean checkClassAnnotationCompliace() {
-        if (mClass.isAnnotation()) {
-            // check annotation
-            for (String inter : implInterfaces) {
-                if ("java.lang.annotation.Annotation".equals(inter)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Checks if the class under test extends the proper classes
-     * according to the API.
-     *
-     * @return true if the class is compliant.
-     */
-    private boolean checkClassExtendsCompliance() {
-        // Nothing to check if it doesn't extend anything.
-        if (mExtendedClass != null) {
-            Class<?> superClass = mClass.getSuperclass();
-
-            while (superClass != null) {
-                if (superClass.getCanonicalName().equals(mExtendedClass)) {
-                    return true;
-                }
-                superClass = superClass.getSuperclass();
-            }
-            // Couldn't find a matching superclass.
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Checks if the class under test implements the proper interfaces
-     * according to the API.
-     *
-     * @return true if the class is compliant
-     */
-    private boolean checkClassImplementsCompliance() {
-        Class<?>[] interfaces = mClass.getInterfaces();
-        Set<String> interFaceSet = new HashSet<String>();
-
-        for (Class<?> c : interfaces) {
-            interFaceSet.add(c.getCanonicalName());
-        }
-
-        for (String inter : implInterfaces) {
-            if (!interFaceSet.contains(inter)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Validate that an interfaces method count is as expected.
-     */
-    private List<String> checkInterfaceMethodCompliance() {
-        List<String> unexpectedMethods = new ArrayList<>();
-        for (Method method : mClass.getDeclaredMethods()) {
-            if (method.isDefault()) {
-                continue;
-            }
-            if (method.isSynthetic()) {
-                continue;
-            }
-            if (method.isBridge()) {
-                continue;
-            }
-            if (HIDDEN_INTERFACE_WHITELIST.contains(method.toGenericString())) {
-                continue;
-            }
-
-            boolean foundMatch = false;
-            for (JDiffMethod jdiffMethod : jDiffMethods) {
-                if (matches(jdiffMethod, method)) {
-                    foundMatch = true;
-                }
-            }
-            if (!foundMatch) {
-                unexpectedMethods.add(method.toGenericString());
-            }
-        }
-
-        return unexpectedMethods;
-
-    }
-
-    /**
-     * Checks that the class found through reflection matches the
-     * specification from the API xml file.
-     */
-    @SuppressWarnings("unchecked")
-    private void checkClassCompliance() {
-        try {
-            mAbsoluteClassName = mPackageName + "." + mShortClassName;
-            mClass = findMatchingClass();
-
-            if (mClass == null) {
-                // No class found, notify the observer according to the class type
-                if (JDiffType.INTERFACE.equals(mClassType)) {
-                    mResultObserver.notifyFailure(FailureType.MISSING_INTERFACE,
-                            mAbsoluteClassName,
-                            "Classloader is unable to find " + mAbsoluteClassName);
-                } else {
-                    mResultObserver.notifyFailure(FailureType.MISSING_CLASS,
-                            mAbsoluteClassName,
-                            "Classloader is unable to find " + mAbsoluteClassName);
-                }
-
-                return;
-            }
-
-            List<String> methods = checkInterfaceMethodCompliance();
-            if (JDiffType.INTERFACE.equals(mClassType) && methods.size() > 0) {
-                mResultObserver.notifyFailure(FailureType.MISMATCH_INTERFACE_METHOD,
-                        mAbsoluteClassName, "Interfaces cannot be modified: "
-                                + mAbsoluteClassName + ": " + methods);
-                return;
-            }
-
-            if (!checkClassModifiersCompliance()) {
-                logMismatchInterfaceSignature(mAbsoluteClassName,
-                        "Non-compatible class found when looking for " +
-                        toSignatureString());
-                return;
-            }
-
-            if (!checkClassAnnotationCompliace()) {
-                logMismatchInterfaceSignature(mAbsoluteClassName,
-                "Annotation mismatch");
-                return;
-            }
-
-            if (!mClass.isAnnotation()) {
-                // check father class
-                if (!checkClassExtendsCompliance()) {
-                    logMismatchInterfaceSignature(mAbsoluteClassName,
-                    "Extends mismatch");
-                    return;
-                }
-
-                // check implements interface
-                if (!checkClassImplementsCompliance()) {
-                    logMismatchInterfaceSignature(mAbsoluteClassName,
-                    "Implements mismatch");
-                    return;
-                }
-            }
-        } catch (Exception e) {
-            loge("Got exception when checking field compliance", e);
-            mResultObserver.notifyFailure(
-                    FailureType.CAUGHT_EXCEPTION,
-                    mAbsoluteClassName,
-                    "Exception!");
-        }
-    }
-
-
-    /**
      * Convert the class into a printable signature string.
      *
      * @return the signature string
      */
     public String toSignatureString() {
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
 
         String accessLevel = convertModifiersToAccessLevel(mModifier);
         if (!"".equals(accessLevel)) {
@@ -1267,92 +447,22 @@
         return sb.toString();
     }
 
-    private void logMismatchInterfaceSignature(String classFullName, String errorMessage) {
-        if (JDiffType.INTERFACE.equals(mClassType)) {
-            mResultObserver.notifyFailure(FailureType.MISMATCH_INTERFACE,
-                    classFullName,
-                    errorMessage);
-        } else {
-            mResultObserver.notifyFailure(FailureType.MISMATCH_CLASS,
-                    classFullName,
-                    errorMessage);
-        }
-    }
-
     /**
      * Sees if the class under test is actually an enum.
      *
      * @return true if this class is enum
      */
-    private boolean isEnumType() {
+    boolean isEnumType() {
         return "java.lang.Enum".equals(mExtendedClass);
     }
 
     /**
-     * Finds the reflected class for the class under test.
-     *
-     * @return the reflected class, or null if not found.
-     */
-    @SuppressWarnings("unchecked")
-    private Class<?> findMatchingClass() {
-        // even if there are no . in the string, split will return an
-        // array of length 1
-        String[] classNameParts = mShortClassName.split("\\.");
-        String currentName = mPackageName + "." + classNameParts[0];
-
-        try {
-            // Check to see if the class we're looking for is the top
-            // level class.
-            Class<?> clz = Class.forName(currentName,
-                    false,
-                    this.getClass().getClassLoader());
-            if (clz.getCanonicalName().equals(mAbsoluteClassName)) {
-                return clz;
-            }
-
-            // Then it must be an inner class.
-            for (int x = 1; x < classNameParts.length; x++) {
-                clz = findInnerClassByName(clz, classNameParts[x]);
-                if (clz == null) {
-                    return null;
-                }
-                if (clz.getCanonicalName().equals(mAbsoluteClassName)) {
-                    return clz;
-                }
-            }
-        } catch (ClassNotFoundException e) {
-            loge("ClassNotFoundException for " + mPackageName + "." + mShortClassName, e);
-            return null;
-        }
-        return null;
-    }
-
-    /**
-     * Searches the class for the specified inner class.
-     *
-     * @param clz the class to search in.
-     * @param simpleName the simpleName of the class to find
-     * @returns the class being searched for, or null if it can't be found.
-     */
-    private Class<?> findInnerClassByName(Class<?> clz, String simpleName) {
-        for (Class<?> c : clz.getDeclaredClasses()) {
-            if (c.getSimpleName().equals(simpleName)) {
-                return c;
-            }
-        }
-        return null;
-    }
-
-    /**
      * Sees if the class under test is actually an annotation.
      *
      * @return true if this class is Annotation.
      */
-    private boolean isAnnotation() {
-        if (implInterfaces.contains("java.lang.annotation.Annotation")) {
-            return true;
-        }
-        return false;
+    boolean isAnnotation() {
+        return implInterfaces.contains("java.lang.annotation.Annotation");
     }
 
     /**
@@ -1360,7 +470,7 @@
      *
      * @return the class name.
      */
-    public String getClassName() {
+    String getClassName() {
         return mShortClassName;
     }
 
@@ -1396,99 +506,11 @@
      *
      * @param extendsClass the class being extended.
      */
-    public void setExtendsClass(String extendsClass) {
+    void setExtendsClass(String extendsClass) {
         mExtendedClass = extendsClass;
     }
 
     /**
-     * Registers a ResultObserver to process the output from the
-     * compliance testing done in this class.
-     *
-     * @param resultObserver the observer to register.
-     */
-    public void registerResultObserver(ResultObserver resultObserver) {
-        mResultObserver = resultObserver;
-    }
-
-    /**
-     * Converts WildcardType array into a jdiff compatible string..
-     * This is a helper function for typeToString.
-     *
-     * @param types array of types to format.
-     * @return the jdiff formatted string.
-     */
-    private static String concatWildcardTypes(Type[] types) {
-        StringBuffer sb = new StringBuffer();
-        int elementNum = 0;
-        for (Type t : types) {
-            sb.append(typeToString(t));
-            if (++elementNum < types.length) {
-                sb.append(" & ");
-            }
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Converts a Type into a jdiff compatible String.  The returned
-     * types from this function should match the same Strings that
-     * jdiff is providing to us.
-     *
-     * @param type the type to convert.
-     * @return the jdiff formatted string.
-     */
-    private static String typeToString(Type type) {
-        if (type instanceof ParameterizedType) {
-            ParameterizedType pt = (ParameterizedType) type;
-
-            StringBuffer sb = new StringBuffer();
-            sb.append(typeToString(pt.getRawType()));
-            sb.append("<");
-
-            int elementNum = 0;
-            Type[] types = pt.getActualTypeArguments();
-            for (Type t : types) {
-                sb.append(typeToString(t));
-                if (++elementNum < types.length) {
-                    sb.append(", ");
-                }
-            }
-
-            sb.append(">");
-            return sb.toString();
-        } else if (type instanceof TypeVariable) {
-            return ((TypeVariable<?>) type).getName();
-        } else if (type instanceof Class) {
-            return ((Class<?>) type).getCanonicalName();
-        } else if (type instanceof GenericArrayType) {
-            String typeName = typeToString(((GenericArrayType) type).getGenericComponentType());
-            return typeName + "[]";
-        } else if (type instanceof WildcardType) {
-            WildcardType wt = (WildcardType) type;
-            Type[] lowerBounds = wt.getLowerBounds();
-            if (lowerBounds.length == 0) {
-                String name = "? extends " + concatWildcardTypes(wt.getUpperBounds());
-
-                // Special case for ?
-                if (name.equals("? extends java.lang.Object")) {
-                    return "?";
-                } else {
-                    return name;
-                }
-            } else {
-                String name = concatWildcardTypes(wt.getUpperBounds()) +
-                " super " +
-                concatWildcardTypes(wt.getLowerBounds());
-                // Another special case for ?
-                name = name.replace("java.lang.Object", "?");
-                return name;
-            }
-        } else {
-            throw new RuntimeException("Got an unknown java.lang.Type");
-        }
-    }
-
-    /**
      * Cleans up jdiff parameters to canonicalize them.
      *
      * @param paramType the parameter from jdiff.
@@ -1502,32 +524,8 @@
             .replace("? super java.lang.Object", "? super ?");
     }
 
-    /**
-     * Scan a class (an its entire inheritance chain) for fields.
-     *
-     * @return a {@link Map} of fieldName to {@link Field}
-     */
-    private static Map<String, Field> buildFieldMap(Class testClass) {
-        Map<String, Field> fieldMap = new HashMap<String, Field>();
-        // Scan the superclass
-        if (testClass.getSuperclass() != null) {
-            fieldMap.putAll(buildFieldMap(testClass.getSuperclass()));
-        }
-
-        // Scan the interfaces
-        for (Class interfaceClass : testClass.getInterfaces()) {
-            fieldMap.putAll(buildFieldMap(interfaceClass));
-        }
-
-        // Check the fields in the test class
-        for (Field field : testClass.getDeclaredFields()) {
-            fieldMap.put(field.getName(), field);
-        }
-
-        return fieldMap;
-    }
-
-    private static void loge(String message, Exception exception) {
-        System.err.println(String.format("%s: %s", message, exception));
+    @Override
+    public String toString() {
+        return mAbsoluteClassName;
     }
 }
diff --git a/tests/signature/src/android/signature/cts/ReflectionHelper.java b/tests/signature/src/android/signature/cts/ReflectionHelper.java
new file mode 100644
index 0000000..54640a3
--- /dev/null
+++ b/tests/signature/src/android/signature/cts/ReflectionHelper.java
@@ -0,0 +1,333 @@
+/*
+ * 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.signature.cts;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Uses reflection to obtain runtime representations of elements in the API.
+ */
+public class ReflectionHelper {
+
+    private static void loge(String message, Exception exception) {
+        System.err.println(String.format("%s: %s", message, exception));
+    }
+
+    /**
+     * Finds the reflected class for the class under test.
+     *
+     * @param classDescription the description of the class to find.
+     * @return the reflected class, or null if not found.
+     */
+    @SuppressWarnings("unchecked")
+    public static Class<?> findMatchingClass(JDiffClassDescription classDescription)
+            throws ClassNotFoundException {
+        // even if there are no . in the string, split will return an
+        // array of length 1
+        String shortClassName = classDescription.getShortClassName();
+        String[] classNameParts = shortClassName.split("\\.");
+        String packageName = classDescription.getPackageName();
+        String currentName = packageName + "." + classNameParts[0];
+
+        Class<?> clz = Class.forName(
+                currentName, false, ReflectionHelper.class.getClassLoader());
+        String absoluteClassName = classDescription.getAbsoluteClassName();
+        if (clz.getCanonicalName().equals(absoluteClassName)) {
+            return clz;
+        }
+
+        // Then it must be an inner class.
+        for (int x = 1; x < classNameParts.length; x++) {
+            clz = findInnerClassByName(clz, classNameParts[x]);
+            if (clz == null) {
+                return null;
+            }
+            if (clz.getCanonicalName().equals(absoluteClassName)) {
+                return clz;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Searches the class for the specified inner class.
+     *
+     * @param clz the class to search in.
+     * @param simpleName the simpleName of the class to find
+     * @return the class being searched for, or null if it can't be found.
+     */
+    private static Class<?> findInnerClassByName(Class<?> clz, String simpleName) {
+        for (Class<?> c : clz.getDeclaredClasses()) {
+            if (c.getSimpleName().equals(simpleName)) {
+                return c;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Searches available constructor.
+     *
+     * @param runtimeClass the class in which to search.
+     * @param jdiffDes constructor description to find.
+     * @return reflected constructor, or null if not found.
+     */
+    @SuppressWarnings("unchecked")
+    static Constructor<?> findMatchingConstructor(Class<?> runtimeClass,
+            JDiffClassDescription.JDiffConstructor jdiffDes) {
+        for (Constructor<?> c : runtimeClass.getDeclaredConstructors()) {
+            Type[] params = c.getGenericParameterTypes();
+            boolean isStaticClass = ((runtimeClass.getModifiers() & Modifier.STATIC) != 0);
+
+            int startParamOffset = 0;
+            int numberOfParams = params.length;
+
+            // non-static inner class -> skip implicit parent pointer
+            // as first arg
+            if (runtimeClass.isMemberClass() && !isStaticClass && params.length >= 1) {
+                startParamOffset = 1;
+                --numberOfParams;
+            }
+
+            ArrayList<String> jdiffParamList = jdiffDes.mParamList;
+            if (jdiffParamList.size() == numberOfParams) {
+                boolean isFound = true;
+                // i counts jdiff params, j counts reflected params
+                int i = 0;
+                int j = startParamOffset;
+                while (i < jdiffParamList.size()) {
+                    if (!compareParam(jdiffParamList.get(i), params[j])) {
+                        isFound = false;
+                        break;
+                    }
+                    ++i;
+                    ++j;
+                }
+                if (isFound) {
+                    return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Compares the parameter from the API and the parameter from
+     * reflection.
+     *
+     * @param jdiffParam param parsed from the API xml file.
+     * @param reflectionParamType param gotten from the Java reflection.
+     * @return True if the two params match, otherwise return false.
+     */
+    private static boolean compareParam(String jdiffParam, Type reflectionParamType) {
+        if (jdiffParam == null) {
+            return false;
+        }
+
+        String reflectionParam = typeToString(reflectionParamType);
+        // Most things aren't varargs, so just do a simple compare
+        // first.
+        if (jdiffParam.equals(reflectionParam)) {
+            return true;
+        }
+
+        // Check for varargs.  jdiff reports varargs as ..., while
+        // reflection reports them as []
+        int jdiffParamEndOffset = jdiffParam.indexOf("...");
+        int reflectionParamEndOffset = reflectionParam.indexOf("[]");
+        if (jdiffParamEndOffset != -1 && reflectionParamEndOffset != -1) {
+            jdiffParam = jdiffParam.substring(0, jdiffParamEndOffset);
+            reflectionParam = reflectionParam.substring(0, reflectionParamEndOffset);
+            return jdiffParam.equals(reflectionParam);
+        }
+
+        return false;
+    }
+
+    /**
+     * Finds the reflected method specified by the method description.
+     *
+     * @param runtimeClass the class in which to search.
+     * @param method description of the method to find
+     * @return the reflected method, or null if not found.
+     */
+    @SuppressWarnings("unchecked")
+    static Method findMatchingMethod(Class<?> runtimeClass,
+            JDiffClassDescription.JDiffMethod method) {
+        Method[] methods = runtimeClass.getDeclaredMethods();
+
+        for (Method m : methods) {
+            if (matches(method, m)) {
+                return m;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Checks if the two types of methods are the same.
+     *
+     * @param jDiffMethod the jDiffMethod to compare
+     * @param reflectedMethod the reflected method to compare
+     * @return true, if both methods are the same
+     */
+    static boolean matches(JDiffClassDescription.JDiffMethod jDiffMethod,
+            Method reflectedMethod) {
+        // If the method names aren't equal, the methods can't match.
+        if (!jDiffMethod.mName.equals(reflectedMethod.getName())) {
+            return false;
+        }
+        String jdiffReturnType = jDiffMethod.mReturnType;
+        String reflectionReturnType = typeToString(reflectedMethod.getGenericReturnType());
+        List<String> jdiffParamList = jDiffMethod.mParamList;
+
+        // Next, compare the return types of the two methods.  If
+        // they aren't equal, the methods can't match.
+        if (!jdiffReturnType.equals(reflectionReturnType)) {
+            return false;
+        }
+
+        Type[] params = reflectedMethod.getGenericParameterTypes();
+
+        // Next, check the method parameters.  If they have different
+        // parameter lengths, the two methods can't match.
+        if (jdiffParamList.size() != params.length) {
+            return false;
+        }
+
+        boolean piecewiseParamsMatch = true;
+
+        // Compare method parameters piecewise and return true if they all match.
+        for (int i = 0; i < jdiffParamList.size(); i++) {
+            piecewiseParamsMatch &= compareParam(jdiffParamList.get(i), params[i]);
+        }
+        if (piecewiseParamsMatch) {
+            return true;
+        }
+
+        /* NOTE: There are cases where piecewise method parameter checking
+         * fails even though the strings are equal, so compare entire strings
+         * against each other. This is not done by default to avoid a
+         * TransactionTooLargeException.
+         * Additionally, this can fail anyway due to extra
+         * information dug up by reflection.
+         *
+         * TODO: fix parameter equality checking and reflection matching
+         * See https://b.corp.google.com/issues/27726349
+         */
+
+        StringBuilder reflectedMethodParams = new StringBuilder("");
+        StringBuilder jdiffMethodParams = new StringBuilder("");
+
+        for (int i = 0; i < jdiffParamList.size(); i++) {
+            jdiffMethodParams.append(jdiffParamList.get(i));
+            reflectedMethodParams.append(params[i]);
+        }
+
+        String jDiffFName = jdiffMethodParams.toString();
+        String refName = reflectedMethodParams.toString();
+
+        return jDiffFName.equals(refName);
+    }
+
+    /**
+     * Converts WildcardType array into a jdiff compatible string..
+     * This is a helper function for typeToString.
+     *
+     * @param types array of types to format.
+     * @return the jdiff formatted string.
+     */
+    private static String concatWildcardTypes(Type[] types) {
+        StringBuilder sb = new StringBuilder();
+        int elementNum = 0;
+        for (Type t : types) {
+            sb.append(typeToString(t));
+            if (++elementNum < types.length) {
+                sb.append(" & ");
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Converts a Type into a jdiff compatible String.  The returned
+     * types from this function should match the same Strings that
+     * jdiff is providing to us.
+     *
+     * @param type the type to convert.
+     * @return the jdiff formatted string.
+     */
+    private static String typeToString(Type type) {
+        if (type instanceof ParameterizedType) {
+            ParameterizedType pt = (ParameterizedType) type;
+
+            StringBuilder sb = new StringBuilder();
+            sb.append(typeToString(pt.getRawType()));
+            sb.append("<");
+
+            int elementNum = 0;
+            Type[] types = pt.getActualTypeArguments();
+            for (Type t : types) {
+                sb.append(typeToString(t));
+                if (++elementNum < types.length) {
+                    sb.append(", ");
+                }
+            }
+
+            sb.append(">");
+            return sb.toString();
+        } else if (type instanceof TypeVariable) {
+            return ((TypeVariable<?>) type).getName();
+        } else if (type instanceof Class) {
+            return ((Class<?>) type).getCanonicalName();
+        } else if (type instanceof GenericArrayType) {
+            String typeName = typeToString(((GenericArrayType) type).getGenericComponentType());
+            return typeName + "[]";
+        } else if (type instanceof WildcardType) {
+            WildcardType wt = (WildcardType) type;
+            Type[] lowerBounds = wt.getLowerBounds();
+            if (lowerBounds.length == 0) {
+                String name = "? extends " + concatWildcardTypes(wt.getUpperBounds());
+
+                // Special case for ?
+                if (name.equals("? extends java.lang.Object")) {
+                    return "?";
+                } else {
+                    return name;
+                }
+            } else {
+                String name = concatWildcardTypes(wt.getUpperBounds()) +
+                        " super " +
+                        concatWildcardTypes(wt.getLowerBounds());
+                // Another special case for ?
+                name = name.replace("java.lang.Object", "?");
+                return name;
+            }
+        } else {
+            throw new RuntimeException("Got an unknown java.lang.Type");
+        }
+    }
+}
diff --git a/tests/signature/src/android/signature/cts/SignatureTest.java b/tests/signature/src/android/signature/cts/SignatureTest.java
deleted file mode 100644
index af82a46..0000000
--- a/tests/signature/src/android/signature/cts/SignatureTest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2011 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.signature.cts;
-
-import static android.signature.cts.CurrentApi.CURRENT_API_FILE;
-import static android.signature.cts.CurrentApi.SYSTEM_CURRENT_API_FILE;
-import static android.signature.cts.CurrentApi.TAG_ROOT;
-import static android.signature.cts.CurrentApi.TAG_PACKAGE;
-import static android.signature.cts.CurrentApi.TAG_CLASS;
-import static android.signature.cts.CurrentApi.TAG_INTERFACE;
-import static android.signature.cts.CurrentApi.TAG_IMPLEMENTS;
-import static android.signature.cts.CurrentApi.TAG_CONSTRUCTOR;
-import static android.signature.cts.CurrentApi.TAG_METHOD;
-import static android.signature.cts.CurrentApi.TAG_PARAM;
-import static android.signature.cts.CurrentApi.TAG_EXCEPTION;
-import static android.signature.cts.CurrentApi.TAG_FIELD;
-
-import static android.signature.cts.CurrentApi.MODIFIER_ABSTRACT;
-import static android.signature.cts.CurrentApi.MODIFIER_FINAL;
-import static android.signature.cts.CurrentApi.MODIFIER_NATIVE;
-import static android.signature.cts.CurrentApi.MODIFIER_PRIVATE;
-import static android.signature.cts.CurrentApi.MODIFIER_PROTECTED;
-import static android.signature.cts.CurrentApi.MODIFIER_PUBLIC;
-import static android.signature.cts.CurrentApi.MODIFIER_STATIC;
-import static android.signature.cts.CurrentApi.MODIFIER_SYNCHRONIZED;
-import static android.signature.cts.CurrentApi.MODIFIER_TRANSIENT;
-import static android.signature.cts.CurrentApi.MODIFIER_VOLATILE;
-import static android.signature.cts.CurrentApi.MODIFIER_VISIBILITY;
-
-import static android.signature.cts.CurrentApi.ATTRIBUTE_NAME;
-import static android.signature.cts.CurrentApi.ATTRIBUTE_EXTENDS;
-import static android.signature.cts.CurrentApi.ATTRIBUTE_TYPE;
-import static android.signature.cts.CurrentApi.ATTRIBUTE_RETURN;
-
-import android.content.res.Resources;
-import android.signature.cts.JDiffClassDescription.JDiffConstructor;
-import android.signature.cts.JDiffClassDescription.JDiffField;
-import android.signature.cts.JDiffClassDescription.JDiffMethod;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Scanner;
-
-/**
- * Performs the signature check via a JUnit test.
- */
-public class SignatureTest extends AndroidTestCase {
-
-    private static final String TAG = SignatureTest.class.getSimpleName();
-
-    private HashSet<String> mKeyTagSet;
-    private TestResultObserver mResultObserver;
-
-    private class TestResultObserver implements ResultObserver {
-        boolean mDidFail = false;
-        StringBuilder mErrorString = new StringBuilder();
-
-        @Override
-        public void notifyFailure(FailureType type, String name, String errorMessage) {
-            mDidFail = true;
-            mErrorString.append("\n");
-            mErrorString.append(type.toString().toLowerCase());
-            mErrorString.append(":\t");
-            mErrorString.append(name);
-            mErrorString.append("\tError: ");
-            mErrorString.append(errorMessage);
-        }
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyTagSet = new HashSet<String>();
-        mKeyTagSet.addAll(Arrays.asList(new String[] {
-                TAG_PACKAGE, TAG_CLASS, TAG_INTERFACE, TAG_IMPLEMENTS, TAG_CONSTRUCTOR,
-                TAG_METHOD, TAG_PARAM, TAG_EXCEPTION, TAG_FIELD }));
-        mResultObserver = new TestResultObserver();
-    }
-
-    /**
-     * Tests that the device's API matches the expected set defined in xml.
-     * <p/>
-     * Will check the entire API, and then report the complete list of failures
-     */
-    public void testSignature() {
-        try {
-            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
-            XmlPullParser parser = factory.newPullParser();
-            parser.setInput(new FileInputStream(new File(CURRENT_API_FILE)), null);
-            start(parser);
-        } catch (Exception e) {
-            mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION, e.getMessage(),
-                    e.getMessage());
-        }
-        if (mResultObserver.mDidFail) {
-            fail(mResultObserver.mErrorString.toString());
-        }
-    }
-
-    private void beginDocument(XmlPullParser parser, String firstElementName)
-            throws XmlPullParserException, IOException {
-        int type;
-        while ((type=parser.next()) != XmlPullParser.START_TAG
-                   && type != XmlPullParser.END_DOCUMENT) { }
-
-        if (type != XmlPullParser.START_TAG) {
-            throw new XmlPullParserException("No start tag found");
-        }
-
-        if (!parser.getName().equals(firstElementName)) {
-            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
-                    ", expected " + firstElementName);
-        }
-    }
-
-    /**
-     * Signature test entry point.
-     */
-    private void start(XmlPullParser parser) throws XmlPullParserException, IOException {
-        logd(String.format("Name: %s", parser.getName()));
-        logd(String.format("Text: %s", parser.getText()));
-        logd(String.format("Namespace: %s", parser.getNamespace()));
-        logd(String.format("Line Number: %s", parser.getLineNumber()));
-        logd(String.format("Column Number: %s", parser.getColumnNumber()));
-        logd(String.format("Position Description: %s", parser.getPositionDescription()));
-        JDiffClassDescription currentClass = null;
-        String currentPackage = "";
-        JDiffMethod currentMethod = null;
-
-        beginDocument(parser, TAG_ROOT);
-        int type;
-        while (true) {
-            type = XmlPullParser.START_DOCUMENT;
-            while ((type=parser.next()) != XmlPullParser.START_TAG
-                       && type != XmlPullParser.END_DOCUMENT
-                       && type != XmlPullParser.END_TAG) {
-
-            }
-
-            if (type == XmlPullParser.END_TAG) {
-                if (TAG_CLASS.equals(parser.getName())
-                        || TAG_INTERFACE.equals(parser.getName())) {
-                    currentClass.checkSignatureCompliance();
-                } else if (TAG_PACKAGE.equals(parser.getName())) {
-                    currentPackage = "";
-                }
-                continue;
-            }
-
-            if (type == XmlPullParser.END_DOCUMENT) {
-                break;
-            }
-
-            String tagname = parser.getName();
-            if (!mKeyTagSet.contains(tagname)) {
-                continue;
-            }
-
-            if (type == XmlPullParser.START_TAG && tagname.equals(TAG_PACKAGE)) {
-                currentPackage = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-            } else if (tagname.equals(TAG_CLASS)) {
-                currentClass = CurrentApi.loadClassInfo(
-                            parser, false, currentPackage, mResultObserver);
-            } else if (tagname.equals(TAG_INTERFACE)) {
-                currentClass = CurrentApi.loadClassInfo(
-                            parser, true, currentPackage, mResultObserver);
-            } else if (tagname.equals(TAG_IMPLEMENTS)) {
-                currentClass.addImplInterface(parser.getAttributeValue(null, ATTRIBUTE_NAME));
-            } else if (tagname.equals(TAG_CONSTRUCTOR)) {
-                JDiffConstructor constructor =
-                        CurrentApi.loadConstructorInfo(parser, currentClass);
-                currentClass.addConstructor(constructor);
-                currentMethod = constructor;
-            } else if (tagname.equals(TAG_METHOD)) {
-                currentMethod = CurrentApi.loadMethodInfo(currentClass.getClassName(), parser);
-                currentClass.addMethod(currentMethod);
-            } else if (tagname.equals(TAG_PARAM)) {
-                currentMethod.addParam(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
-            } else if (tagname.equals(TAG_EXCEPTION)) {
-                currentMethod.addException(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
-            } else if (tagname.equals(TAG_FIELD)) {
-                JDiffField field = CurrentApi.loadFieldInfo(currentClass.getClassName(), parser);
-                currentClass.addField(field);
-            } else {
-                throw new RuntimeException(
-                        "unknown tag exception:" + tagname);
-            }
-            if (currentPackage != null) {
-                logd(String.format("currentPackage: %s", currentPackage));
-            }
-            if (currentClass != null) {
-                logd(String.format("currentClass: %s", currentClass.toSignatureString()));
-            }
-            if (currentMethod != null) {
-                logd(String.format("currentMethod: %s", currentMethod.toSignatureString()));
-            }
-        }
-    }
-
-    public static void loge(String msg, Exception e) {
-        Log.e(TAG, msg, e);
-    }
-
-    public static void logd(String msg) {
-        Log.d(TAG, msg);
-    }
-}
diff --git a/tests/signature/tests/src/android/signature/cts/tests/AllTests.java b/tests/signature/tests/src/android/signature/cts/tests/AllTests.java
index 56916f4..71b1e35 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/AllTests.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/AllTests.java
@@ -27,7 +27,7 @@
     public AllTests() {
         super();
 
-        addTestSuite(JDiffClassDescriptionTest.class);
+        addTestSuite(ApiComplianceCheckerTest.class);
     }
 
     public static Test suite() {
diff --git a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
similarity index 88%
rename from tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
rename to tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
index 6e477ae..71d2e37 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
@@ -16,6 +16,7 @@
 
 package android.signature.cts.tests;
 
+import android.signature.cts.ApiComplianceChecker;
 import android.signature.cts.FailureType;
 import android.signature.cts.JDiffClassDescription;
 import android.signature.cts.ResultObserver;
@@ -28,7 +29,7 @@
 /**
  * Test class for JDiffClassDescription.
  */
-public class JDiffClassDescriptionTest extends TestCase {
+public class ApiComplianceCheckerTest extends TestCase {
 
     private static final String VALUE = "VALUE";
 
@@ -43,7 +44,7 @@
         private FailureType expectedType;
         private boolean failureSeen;
 
-        public ExpectFailure(FailureType expectedType) {
+        ExpectFailure(FailureType expectedType) {
             this.expectedType = expectedType;
         }
 
@@ -61,28 +62,30 @@
             }
         }
 
-        public void validate() {
+        void validate() {
             Assert.assertTrue(failureSeen);
         }
     }
 
+    private void checkSignatureCompliance(JDiffClassDescription classDescription) {
+        ResultObserver resultObserver = new NoFailures();
+        checkSignatureCompliance(classDescription, resultObserver);
+    }
+
+    private void checkSignatureCompliance(JDiffClassDescription classDescription,
+            ResultObserver resultObserver) {
+        ApiComplianceChecker complianceChecker = new ApiComplianceChecker(resultObserver);
+        complianceChecker.checkSignatureCompliance(classDescription);
+    }
+
     /**
      * Create the JDiffClassDescription for "NormalClass".
      *
      * @return the new JDiffClassDescription
      */
     private JDiffClassDescription createNormalClass() {
-        return createNormalClass(new NoFailures());
-    }
-
-    /**
-     * Create the JDiffClassDescription for "NormalClass".
-     *
-     * @return the new JDiffClassDescription
-     */
-    private JDiffClassDescription createNormalClass(ResultObserver observer) {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NormalClass", observer);
+                "android.signature.cts.tests.data", "NormalClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC);
         return clz;
@@ -90,16 +93,16 @@
 
     public void testNormalClassCompliance() {
         JDiffClassDescription clz = createNormalClass();
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(clz.toSignatureString(), "public class NormalClass");
     }
 
     public void testMissingClass() {
         ExpectFailure observer = new ExpectFailure(FailureType.MISSING_CLASS);
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NoSuchClass", observer);
+                "android.signature.cts.tests.data", "NoSuchClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz, observer);
         observer.validate();
     }
 
@@ -108,7 +111,7 @@
         JDiffClassDescription.JDiffConstructor constructor =
                 new JDiffClassDescription.JDiffConstructor("NormalClass", Modifier.PUBLIC);
         clz.addConstructor(constructor);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(constructor.toSignatureString(), "public NormalClass()");
     }
 
@@ -118,7 +121,7 @@
                 new JDiffClassDescription.JDiffConstructor("NormalClass", Modifier.PRIVATE);
         constructor.addParam("java.lang.String");
         clz.addConstructor(constructor);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(constructor.toSignatureString(), "private NormalClass(java.lang.String)");
     }
 
@@ -130,7 +133,7 @@
         constructor.addParam("java.lang.String");
         constructor.addException("android.signature.cts.tests.data.NormalException");
         clz.addConstructor(constructor);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(constructor.toSignatureString(),
                 "protected NormalClass(java.lang.String, java.lang.String) " +
                 "throws android.signature.cts.tests.data.NormalException");
@@ -144,7 +147,7 @@
         constructor.addParam("java.lang.String");
         constructor.addParam("java.lang.String");
         clz.addConstructor(constructor);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(constructor.toSignatureString(),
                 "NormalClass(java.lang.String, java.lang.String, java.lang.String)");
     }
@@ -154,7 +157,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "staticMethod", Modifier.STATIC | Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "public static void staticMethod()");
     }
 
@@ -163,7 +166,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "syncMethod", Modifier.SYNCHRONIZED | Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "public synchronized void syncMethod()");
     }
 
@@ -172,7 +175,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "packageProtectedMethod", 0, "boolean");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "boolean packageProtectedMethod()");
     }
 
@@ -181,7 +184,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "privateMethod", Modifier.PRIVATE, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "private void privateMethod()");
     }
 
@@ -190,7 +193,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "protectedMethod", Modifier.PROTECTED, "java.lang.String");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "protected java.lang.String protectedMethod()");
     }
 
@@ -200,7 +203,7 @@
                 "throwsMethod", Modifier.PUBLIC, "void");
         method.addException("android.signature.cts.tests.data.NormalException");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "public void throwsMethod() " +
                 "throws android.signature.cts.tests.data.NormalException");
     }
@@ -210,7 +213,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "nativeMethod", Modifier.PUBLIC | Modifier.NATIVE, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "public native void nativeMethod()");
     }
 
@@ -219,7 +222,7 @@
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "FINAL_FIELD", "java.lang.String", Modifier.PUBLIC | Modifier.FINAL, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(), "public final java.lang.String FINAL_FIELD");
     }
 
@@ -228,7 +231,7 @@
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "STATIC_FIELD", "java.lang.String", Modifier.PUBLIC | Modifier.STATIC, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(), "public static java.lang.String STATIC_FIELD");
     }
 
@@ -237,7 +240,7 @@
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "VOLATILE_FIELD", "java.lang.String", Modifier.PUBLIC | Modifier.VOLATILE, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(), "public volatile java.lang.String VOLATILE_FIELD");
     }
 
@@ -247,7 +250,7 @@
                 "TRANSIENT_FIELD", "java.lang.String",
                 Modifier.PUBLIC | Modifier.TRANSIENT, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(),
                 "public transient java.lang.String TRANSIENT_FIELD");
     }
@@ -257,7 +260,7 @@
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "PACAKGE_FIELD", "java.lang.String", 0, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(), "java.lang.String PACAKGE_FIELD");
     }
 
@@ -266,7 +269,7 @@
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "PRIVATE_FIELD", "java.lang.String", Modifier.PRIVATE, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(), "private java.lang.String PRIVATE_FIELD");
     }
 
@@ -275,7 +278,7 @@
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "PROTECTED_FIELD", "java.lang.String", Modifier.PROTECTED, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(), "protected java.lang.String PROTECTED_FIELD");
     }
 
@@ -285,19 +288,19 @@
                 "VALUE_FIELD", "java.lang.String",
                 Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"\\u2708\"");
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(),
                 "public static final java.lang.String VALUE_FIELD");
     }
 
     public void testFieldValueChanged() {
         ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_FIELD);
-        JDiffClassDescription clz = createNormalClass(observer);
+        JDiffClassDescription clz = createNormalClass();
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "VALUE_FIELD", "java.lang.String",
                 Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"&#9992;\"");
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz, observer);
         assertEquals(field.toSignatureString(),
                 "public static final java.lang.String VALUE_FIELD");
         observer.validate();
@@ -305,60 +308,60 @@
 
     public void testInnerClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NormalClass.InnerClass", new NoFailures());
+                "android.signature.cts.tests.data", "NormalClass.InnerClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC);
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "innerClassData", "java.lang.String", Modifier.PRIVATE, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(clz.toSignatureString(), "public class NormalClass.InnerClass");
     }
 
     public void testInnerInnerClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NormalClass.InnerClass.InnerInnerClass",
-                new NoFailures());
+                "android.signature.cts.tests.data", "NormalClass.InnerClass.InnerInnerClass"
+        );
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC);
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "innerInnerClassData", "java.lang.String", Modifier.PRIVATE, VALUE);
         clz.addField(field);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(clz.toSignatureString(),
                 "public class NormalClass.InnerClass.InnerInnerClass");
     }
 
     public void testInnerInterface() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NormalClass.InnerInterface", new NoFailures());
+                "android.signature.cts.tests.data", "NormalClass.InnerInterface");
         clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
         clz.setModifier(Modifier.PUBLIC | Modifier.STATIC | Modifier.ABSTRACT);
         clz.addMethod(
                 new JDiffClassDescription.JDiffMethod("doSomething",
                     Modifier.PUBLIC | Modifier.ABSTRACT, "void"));
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(clz.toSignatureString(), "public interface NormalClass.InnerInterface");
     }
 
     public void testInterface() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NormalInterface", new NoFailures());
+                "android.signature.cts.tests.data", "NormalInterface");
         clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
         clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
         clz.addMethod(
                 new JDiffClassDescription.JDiffMethod("doSomething",
                     Modifier.ABSTRACT| Modifier.PUBLIC, "void"));
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(clz.toSignatureString(), "public interface NormalInterface");
     }
 
     public void testFinalClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "FinalClass", new NoFailures());
+                "android.signature.cts.tests.data", "FinalClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(clz.toSignatureString(), "public final class FinalClass");
     }
 
@@ -368,11 +371,11 @@
      */
     public void testAddingSync() {
         ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD);
-        JDiffClassDescription clz = createNormalClass(observer);
+        JDiffClassDescription clz = createNormalClass();
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "syncMethod", Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz, observer);
         observer.validate();
     }
 
@@ -385,7 +388,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "notSyncMethod", Modifier.SYNCHRONIZED | Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
     }
 
     /**
@@ -396,7 +399,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "nativeMethod", Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
     }
 
     /**
@@ -407,15 +410,15 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "notNativeMethod", Modifier.NATIVE | Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
     }
 
     public void testAbstractClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "AbstractClass", new NoFailures());
+                "android.signature.cts.tests.data", "AbstractClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(clz.toSignatureString(), "public abstract class AbstractClass");
     }
 
@@ -424,10 +427,10 @@
      */
     public void testRemovingAbstractFromAClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NormalClass", new NoFailures());
+                "android.signature.cts.tests.data", "NormalClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
     }
 
     /**
@@ -436,10 +439,10 @@
     public void testAddingAbstractToAClass() {
         ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS);
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "AbstractClass", observer);
+                "android.signature.cts.tests.data", "AbstractClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz, observer);
         observer.validate();
     }
 
@@ -448,7 +451,7 @@
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "finalMethod", Modifier.PUBLIC | Modifier.FINAL, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
         assertEquals(method.toSignatureString(), "public final void finalMethod()");
     }
 
@@ -458,13 +461,13 @@
      */
     public void testAddingFinalToAMethodInAFinalClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "FinalClass", new NoFailures());
+                "android.signature.cts.tests.data", "FinalClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "finalMethod", Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
     }
 
     /**
@@ -473,13 +476,13 @@
      */
     public void testRemovingFinalToAMethodInAFinalClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "FinalClass", new NoFailures());
+                "android.signature.cts.tests.data", "FinalClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "nonFinalMethod", Modifier.PUBLIC | Modifier.FINAL, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz);
     }
 
     /**
@@ -489,13 +492,13 @@
     public void testAddingFinalToAMethodInANonFinalClass() {
         ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD);
         JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NormalClass", observer);
+                "android.signature.cts.tests.data", "NormalClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC);
         JDiffClassDescription.JDiffMethod method = new JDiffClassDescription.JDiffMethod(
                 "finalMethod", Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        clz.checkSignatureCompliance();
+        checkSignatureCompliance(clz, observer);
         observer.validate();
     }
 }
diff --git a/tests/simplecpu/Android.mk b/tests/simplecpu/Android.mk
index 1d006e1..618a9bc 100644
--- a/tests/simplecpu/Android.mk
+++ b/tests/simplecpu/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_PACKAGE_NAME := CtsSimpleCpuTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := 16
 
diff --git a/tests/simplecpu/jni/Android.mk b/tests/simplecpu/jni/Android.mk
index 877f1b6..c5f072e 100644
--- a/tests/simplecpu/jni/Android.mk
+++ b/tests/simplecpu/jni/Android.mk
@@ -26,4 +26,6 @@
 
 LOCAL_SDK_VERSION := 14
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/accounts/Android.mk b/tests/tests/accounts/Android.mk
index a3c1f92..f5ac4fa 100644
--- a/tests/tests/accounts/Android.mk
+++ b/tests/tests/accounts/Android.mk
@@ -24,6 +24,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     CtsAccountTestsCommon ctstestrunner legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := legacy-android-test
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
@@ -35,7 +37,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk
index fda4bd0..924b378 100644
--- a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_PACKAGE_NAME := CtsUnaffiliatedAccountAuthenticators
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
index 795fcd6..c940c3f 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -2297,9 +2297,32 @@
         try {
             StrictMode.setThreadPolicy(
                     new StrictMode.ThreadPolicy.Builder().detectDiskReads().penaltyDeath().build());
+            // getAccounts()
             Account[] accounts = am.getAccounts();
             assertNotNull(accounts);
             assertTrue(accounts.length > 0);
+
+            // getAccountsAndVisibilityForPackage(...)
+            Map<Account, Integer> accountsAndVisibility =
+                am.getAccountsAndVisibilityForPackage(PACKAGE_NAME_PRIVILEGED, ACCOUNT_TYPE);
+            assertNotNull(accountsAndVisibility);
+            assertTrue(accountsAndVisibility.size() > 0);
+
+            // getAccountsByType(...)
+            Account[] accountsByType = am.getAccountsByType(ACCOUNT_TYPE);
+            assertNotNull(accountsByType);
+            assertTrue(accountsByType.length > 0);
+
+            // getAccountsByTypeForPackage(...)
+            Account[] accountsByTypeForPackage =
+                am.getAccountsByTypeForPackage(ACCOUNT_TYPE, PACKAGE_NAME_PRIVILEGED);
+            assertNotNull(accountsByTypeForPackage);
+            assertTrue(accountsByTypeForPackage.length > 0);
+
+            // getAccountsByTypeAndFeatures(...)
+            am.getAccountsByTypeAndFeatures(ACCOUNT_TYPE, null /* features */, null, null);
+            am.getAccountsByTypeAndFeatures(ACCOUNT_TYPE, REQUIRED_FEATURES, null, null);
+
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
         }
diff --git a/tests/tests/alarmclock/Android.mk b/tests/tests/alarmclock/Android.mk
index 7810ad8..adfd51f 100644
--- a/tests/tests/alarmclock/Android.mk
+++ b/tests/tests/alarmclock/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/alarmclock/common/Android.mk b/tests/tests/alarmclock/common/Android.mk
index 7e95cff..039ca5c 100644
--- a/tests/tests/alarmclock/common/Android.mk
+++ b/tests/tests/alarmclock/common/Android.mk
@@ -28,6 +28,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/alarmclock/service/Android.mk b/tests/tests/alarmclock/service/Android.mk
index 645393b..3873ddb 100644
--- a/tests/tests/alarmclock/service/Android.mk
+++ b/tests/tests/alarmclock/service/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/animation/Android.mk b/tests/tests/animation/Android.mk
index 31c1253..c625cbe6 100644
--- a/tests/tests/animation/Android.mk
+++ b/tests/tests/animation/Android.mk
@@ -38,6 +38,6 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app.usage/Android.mk b/tests/tests/app.usage/Android.mk
index 5a97450..84559fa 100644
--- a/tests/tests/app.usage/Android.mk
+++ b/tests/tests/app.usage/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
index fcb1d5a..b475cea 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
@@ -281,7 +281,8 @@
                 exerciseRemoteHost(network, mUrl);
                 mEndTime = System.currentTimeMillis() + mTolerance;
                 success = true;
-                metered = mCm.getNetworkInfo(network).isMetered();
+                metered = !mCm.getNetworkCapabilities(network)
+                        .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
                 synchronized(NetworkUsageStatsTest.this) {
                     NetworkUsageStatsTest.this.notify();
                 }
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index b85609e..bd679a4 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/appwidget/Android.mk b/tests/tests/appwidget/Android.mk
index c4abdeb..5df6046 100644
--- a/tests/tests/appwidget/Android.mk
+++ b/tests/tests/appwidget/Android.mk
@@ -32,7 +32,7 @@
     legacy-android-test
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/appwidget/packages/launchermanifest/Android.mk b/tests/tests/appwidget/packages/launchermanifest/Android.mk
index 01a48d5..f949836 100644
--- a/tests/tests/appwidget/packages/launchermanifest/Android.mk
+++ b/tests/tests/appwidget/packages/launchermanifest/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.appwidget.cts.packages.launcher1
 
@@ -54,7 +54,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.appwidget.cts.packages.launcher2
 
@@ -75,7 +75,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.appwidget.cts.packages.launcher3
 
diff --git a/tests/tests/assist/Android.mk b/tests/tests/assist/Android.mk
index 49ec503..6aa818e 100644
--- a/tests/tests/assist/Android.mk
+++ b/tests/tests/assist/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon ctstestrunner compatibility-device-util
 
diff --git a/tests/tests/assist/service/Android.mk b/tests/tests/assist/service/Android.mk
index de3fdca..218ed6b 100644
--- a/tests/tests/assist/service/Android.mk
+++ b/tests/tests/assist/service/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsAssistService
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/assist/testapp/Android.mk b/tests/tests/assist/testapp/Android.mk
index 284da7b..f179ec3 100644
--- a/tests/tests/assist/testapp/Android.mk
+++ b/tests/tests/assist/testapp/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsAssistApp
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/background/Android.mk b/tests/tests/background/Android.mk
index 37791ce..c5a98aa 100755
--- a/tests/tests/background/Android.mk
+++ b/tests/tests/background/Android.mk
@@ -34,7 +34,7 @@
 
 LOCAL_PACKAGE_NAME := CtsBackgroundRestrictionsTestCases
 
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/tests/bionic/Android.mk b/tests/tests/bionic/Android.mk
index b7ad767..00448f3 100644
--- a/tests/tests/bionic/Android.mk
+++ b/tests/tests/bionic/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_CXX_STL := libc++_static
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CTS_TEST_PACKAGE := android.bionic
 
diff --git a/tests/tests/bluetooth/Android.mk b/tests/tests/bluetooth/Android.mk
index 0060a38..1af4a3f 100644
--- a/tests/tests/bluetooth/Android.mk
+++ b/tests/tests/bluetooth/Android.mk
@@ -32,6 +32,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/calendarcommon/Android.mk b/tests/tests/calendarcommon/Android.mk
index 042e260..18ae49e 100644
--- a/tests/tests/calendarcommon/Android.mk
+++ b/tests/tests/calendarcommon/Android.mk
@@ -27,11 +27,13 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test
 
+LOCAL_JAVA_LIBRARIES := legacy-android-test
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/car/Android.mk b/tests/tests/car/Android.mk
index 246409b..db12143 100644
--- a/tests/tests/car/Android.mk
+++ b/tests/tests/car/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/carrierapi/Android.mk b/tests/tests/carrierapi/Android.mk
index f66bfca..954ae14 100644
--- a/tests/tests/carrierapi/Android.mk
+++ b/tests/tests/carrierapi/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_PACKAGE_NAME := CtsCarrierApiTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_LIBRARIES += android.test.runner telephony-common
 
diff --git a/tests/tests/colormode/Android.mk b/tests/tests/colormode/Android.mk
index f0741aa..a506fa5 100644
--- a/tests/tests/colormode/Android.mk
+++ b/tests/tests/colormode/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsColorModeTestCases
 
diff --git a/tests/tests/colormode/src/android/colormode/cts/DefaultColorModeTest.java b/tests/tests/colormode/src/android/colormode/cts/DefaultColorModeTest.java
index 06273eb..4d076f8 100644
--- a/tests/tests/colormode/src/android/colormode/cts/DefaultColorModeTest.java
+++ b/tests/tests/colormode/src/android/colormode/cts/DefaultColorModeTest.java
@@ -30,6 +30,7 @@
 import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 
 @MediumTest
 @RunWith(AndroidJUnit4.class)
@@ -53,5 +54,7 @@
 
         Window window = mActivity.getWindow();
         assertEquals(ActivityInfo.COLOR_MODE_DEFAULT, window.getAttributes().getColorMode());
+
+        assertFalse(window.isWideColorGamut());
     }
 }
diff --git a/tests/tests/contactsproviderwipe/Android.mk b/tests/tests/contactsproviderwipe/Android.mk
index a4a01b8..d843256 100644
--- a/tests/tests/contactsproviderwipe/Android.mk
+++ b/tests/tests/contactsproviderwipe/Android.mk
@@ -34,7 +34,7 @@
 
 LOCAL_PACKAGE_NAME := CtsContactsProviderWipe
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index 192c745..3b64fa1 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -49,7 +49,7 @@
 LOCAL_PACKAGE_NAME := CtsContentTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/database/Android.mk b/tests/tests/database/Android.mk
index 4378dc5..1ebbe2d 100644
--- a/tests/tests/database/Android.mk
+++ b/tests/tests/database/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_PACKAGE_NAME := CtsDatabaseTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/debug/Android.mk b/tests/tests/debug/Android.mk
index ff2d50f..f1b9b27 100644
--- a/tests/tests/debug/Android.mk
+++ b/tests/tests/debug/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
diff --git a/tests/tests/display/Android.mk b/tests/tests/display/Android.mk
index ab7693c..53ae177 100644
--- a/tests/tests/display/Android.mk
+++ b/tests/tests/display/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test legacy-android-test
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDisplayTestCases
 
diff --git a/tests/tests/dpi/Android.mk b/tests/tests/dpi/Android.mk
index cfd8165..8bb7d64 100644
--- a/tests/tests/dpi/Android.mk
+++ b/tests/tests/dpi/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/dpi2/Android.mk b/tests/tests/dpi2/Android.mk
index 1fcedf1..dcd2c0f 100644
--- a/tests/tests/dpi2/Android.mk
+++ b/tests/tests/dpi2/Android.mk
@@ -20,6 +20,8 @@
 # We use the DefaultManifestAttributesTest from the android.cts.dpi package.
 LOCAL_STATIC_JAVA_LIBRARIES := android.cts.dpi ctstestrunner junit
 
+LOCAL_JAVA_LIBRARIES := legacy-android-test
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsDpiTestCases2
@@ -31,6 +33,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/dreams/Android.mk b/tests/tests/dreams/Android.mk
index 5ae5d85..383c9c3 100644
--- a/tests/tests/dreams/Android.mk
+++ b/tests/tests/dreams/Android.mk
@@ -34,6 +34,6 @@
 #LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/drm/Android.mk b/tests/tests/drm/Android.mk
index a915062..13ac8d6 100644
--- a/tests/tests/drm/Android.mk
+++ b/tests/tests/drm/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsDrmTestCases
 
diff --git a/tests/tests/drm/jni/Android.mk b/tests/tests/drm/jni/Android.mk
index 87f00a4..fe9a041 100644
--- a/tests/tests/drm/jni/Android.mk
+++ b/tests/tests/drm/jni/Android.mk
@@ -30,4 +30,6 @@
 LOCAL_SHARED_LIBRARIES := liblog libdl
 LOCAL_SDK_VERSION := 23
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/effect/Android.mk b/tests/tests/effect/Android.mk
index bf78071..adf2baa 100644
--- a/tests/tests/effect/Android.mk
+++ b/tests/tests/effect/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/externalservice/Android.mk b/tests/tests/externalservice/Android.mk
index cc9c518..62afaad 100644
--- a/tests/tests/externalservice/Android.mk
+++ b/tests/tests/externalservice/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsExternalServiceTestCases
 
diff --git a/tests/tests/externalservice/service/Android.mk b/tests/tests/externalservice/service/Android.mk
index c2cea8a..9fc0033 100644
--- a/tests/tests/externalservice/service/Android.mk
+++ b/tests/tests/externalservice/service/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsExternalServiceService
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/gesture/Android.mk b/tests/tests/gesture/Android.mk
index 3ac8ca3..b7bd036 100755
--- a/tests/tests/gesture/Android.mk
+++ b/tests/tests/gesture/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsGestureTestCases
 
diff --git a/tests/tests/graphics/Android.mk b/tests/tests/graphics/Android.mk
index 6ac89fe..b54d4fd 100644
--- a/tests/tests/graphics/Android.mk
+++ b/tests/tests/graphics/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_PACKAGE_NAME := CtsGraphicsTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Enforce public / test api only
 LOCAL_SDK_VERSION := test_current
diff --git a/tests/tests/graphics/AndroidTest.xml b/tests/tests/graphics/AndroidTest.xml
index 81a7045..baa1e70 100644
--- a/tests/tests/graphics/AndroidTest.xml
+++ b/tests/tests/graphics/AndroidTest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Graphics test cases">
-    <option name="config-descriptor:metadata" key="component" value="graphics" />
+    <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsGraphicsTestCases.apk" />
diff --git a/tests/tests/graphics/jni/Android.mk b/tests/tests/graphics/jni/Android.mk
index 629ae64..ff7d081 100644
--- a/tests/tests/graphics/jni/Android.mk
+++ b/tests/tests/graphics/jni/Android.mk
@@ -24,12 +24,13 @@
 	CtsGraphicsJniOnLoad.cpp \
 	android_graphics_cts_ANativeWindowTest.cpp \
 	android_graphics_cts_BitmapTest.cpp \
+	android_graphics_cts_SyncTest.cpp \
 	android_graphics_cts_VulkanFeaturesTest.cpp
 
-LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -std=c++14 -Wall -Werror
 
 LOCAL_STATIC_LIBRARIES := libvkjson_ndk
-LOCAL_SHARED_LIBRARIES := libandroid libvulkan libnativewindow liblog libdl libjnigraphics
+LOCAL_SHARED_LIBRARIES := libandroid libvulkan libnativewindow libsync liblog libdl libjnigraphics
 LOCAL_NDK_STL_VARIANT := c++_static
 
 LOCAL_SDK_VERSION := current
diff --git a/tests/tests/graphics/jni/android_graphics_cts_SyncTest.cpp b/tests/tests/graphics/jni/android_graphics_cts_SyncTest.cpp
new file mode 100644
index 0000000..aeea02c
--- /dev/null
+++ b/tests/tests/graphics/jni/android_graphics_cts_SyncTest.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ *
+ */
+
+#define LOG_TAG "SyncTest"
+
+#include <poll.h>
+#include <unistd.h>
+
+#include <array>
+#include <memory>
+
+#include <jni.h>
+
+#include <android/sync.h>
+
+namespace {
+
+enum {
+    STATUS_ERROR = -1,
+    STATUS_UNSIGNALED = 0,
+    STATUS_SIGNALED = 1,
+};
+
+jboolean syncPoll(JNIEnv* env, jclass /*clazz*/, jintArray fds_array, jintArray status_array) {
+    jsize n = env->GetArrayLength(fds_array);
+    if (env->GetArrayLength(status_array) != n)
+        return JNI_FALSE;
+    std::unique_ptr<pollfd[]> pollfds = std::make_unique<pollfd[]>(n);
+
+    jint* fds = static_cast<jint*>(env->GetPrimitiveArrayCritical(fds_array, nullptr));
+    for (jsize i = 0; i < n; i++) {
+        pollfds[i].fd = fds[i];
+        pollfds[i].events = POLLIN;
+    }
+    env->ReleasePrimitiveArrayCritical(fds_array, fds, 0);
+
+    int ret;
+    do {
+        ret = poll(pollfds.get(), n, -1 /* infinite timeout */);
+    } while (ret == -1 && errno == EINTR);
+    if (ret == -1)
+        return JNI_FALSE;
+
+    jint* status = static_cast<jint*>(env->GetPrimitiveArrayCritical(status_array, nullptr));
+    for (jsize i = 0; i < n; i++) {
+        if (pollfds[i].fd < 0)
+            continue;
+        if ((pollfds[i].revents & (POLLERR | POLLNVAL)) != 0)
+            status[i] = STATUS_ERROR;
+        else if ((pollfds[i].revents & POLLIN) != 0)
+            status[i] = STATUS_SIGNALED;
+        else
+            status[i] = STATUS_UNSIGNALED;
+    }
+    env->ReleasePrimitiveArrayCritical(status_array, status, 0);
+
+    return JNI_TRUE;
+}
+
+jint syncMerge(JNIEnv* env, jclass /*clazz*/, jstring nameStr, jint fd1, jint fd2) {
+    const char* name = env->GetStringUTFChars(nameStr, nullptr);
+    int32_t result_fd = sync_merge(name, fd1, fd2);
+    env->ReleaseStringUTFChars(nameStr, name);
+    return result_fd;
+}
+
+jobject syncFileInfo(JNIEnv* /*env*/, jclass /*clazz*/, jint fd) {
+    auto info = sync_file_info(fd);
+    if (!info) return nullptr;
+    // TODO: convert to SyncFileInfo
+    sync_file_info_free(info);
+    return nullptr;
+}
+
+void syncClose(int fd) {
+    close(fd);
+}
+
+const std::array<JNINativeMethod, 4> JNI_METHODS = {{
+    { "nSyncPoll", "([I[I)Z", (void*)syncPoll },
+    { "nSyncMerge", "(Ljava/lang/String;II)I", (void*)syncMerge },
+    { "nSyncFileInfo", "(I)Landroid/graphics/cts/SyncTest/SyncFileInfo;", (void*)syncFileInfo },
+    { "nSyncClose", "(I)V", (void*)syncClose },
+}};
+
+}
+
+int register_android_graphics_cts_SyncTest(JNIEnv* env) {
+    jclass clazz = env->FindClass("android/graphics/cts/SyncTest");
+    return env->RegisterNatives(clazz, JNI_METHODS.data(), JNI_METHODS.size());
+}
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_160.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_160.png
deleted file mode 100644
index de48ed9..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_160.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_320.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_320.png
deleted file mode 100644
index 0682813..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_320.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_80.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_80.png
deleted file mode 100644
index 5588a5a..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_density_golden_80.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_160.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_160.png
deleted file mode 100644
index 2e77270..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_160.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_320.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_320.png
deleted file mode 100644
index b5c328b..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_320.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_80.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_80.png
deleted file mode 100644
index a755249..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_80.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_160.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_160.png
deleted file mode 100644
index 2e77270..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_160.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_320.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_320.png
deleted file mode 100644
index d6f5cce..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_320.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_80.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_80.png
deleted file mode 100644
index 3c5f37e..0000000
--- a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_80.png
+++ /dev/null
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 5454e2f..4617f62 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 ea6441a..4d6b84d 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 54fbca7..c6540e8 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 40432cd..491e73e 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 06eccb8..e335a92 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 64a6476..57f2ae3 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/bitmap_density_internal.png b/tests/tests/graphics/res/drawable/bitmap_density_internal.png
deleted file mode 100644
index a4add51..0000000
--- a/tests/tests/graphics/res/drawable/bitmap_density_internal.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_am_density_internal.png b/tests/tests/graphics/res/drawable/bitmap_shader_am_density_internal.png
deleted file mode 100644
index b6d4d89..0000000
--- a/tests/tests/graphics/res/drawable/bitmap_shader_am_density_internal.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_density_internal.png b/tests/tests/graphics/res/drawable/bitmap_shader_density_internal.png
deleted file mode 100644
index b6d4d89..0000000
--- a/tests/tests/graphics/res/drawable/bitmap_shader_density_internal.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 9dafaca..40675853 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -615,19 +615,13 @@
         verifyScaled(BitmapFactory.decodeStream(obtainInputStream(), null, scaledOpt));
     }
 
-    // Test that writing an index8 bitmap to a Parcel succeeds.
     @Test
     public void testParcel() {
-        // Turn off scaling, which would convert to an 8888 bitmap, which does not expose
-        // the bug.
         BitmapFactory.Options opts = new BitmapFactory.Options();
         opts.inScaled = false;
         Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.gif_test, opts);
         assertNotNull(b);
 
-        // index8 has no Java equivalent, so the Config will be null.
-        assertNull(b.getConfig());
-
         Parcel p = Parcel.obtain();
         b.writeToParcel(p, 0);
 
@@ -635,9 +629,6 @@
         Bitmap b2 = Bitmap.CREATOR.createFromParcel(p);
         compareBitmaps(b, b2, 0, true, true);
 
-        // When this failed previously, the bitmap was missing a colortable, resulting in a crash
-        // attempting to compress by dereferencing a null pointer. Compress to verify that we do
-        // not crash, but succeed instead.
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         assertTrue(b2.compress(Bitmap.CompressFormat.JPEG, 50, baos));
     }
@@ -665,17 +656,16 @@
         //     most natural match for the encoded data.
         // Options.inPreferredConfig = null
         //     We will decode to whichever Config is the most natural match with the
-        //     encoded data.  This could be 8-bit indices into a color table (call this
-        //     INDEX_8), ALPHA_8 (gray), or ARGB_8888.
+        //     encoded data.  This could be ALPHA_8 (gray) or ARGB_8888.
         //
         // This test ensures that images are decoded to the intended Config and that the
         // decodes match regardless of the Config.
-        decodeConfigs(R.drawable.alpha, 31, 31, true, false, false);
-        decodeConfigs(R.drawable.baseline_jpeg, 1280, 960, false, false, false);
-        decodeConfigs(R.drawable.bmp_test, 320, 240, false, false, false);
-        decodeConfigs(R.drawable.scaled2, 6, 8, false, false, true);
-        decodeConfigs(R.drawable.grayscale_jpg, 128, 128, false, true, false);
-        decodeConfigs(R.drawable.grayscale_png, 128, 128, false, true, false);
+        decodeConfigs(R.drawable.alpha, 31, 31, true, false);
+        decodeConfigs(R.drawable.baseline_jpeg, 1280, 960, false, false);
+        decodeConfigs(R.drawable.bmp_test, 320, 240, false, false);
+        decodeConfigs(R.drawable.scaled2, 6, 8, false, false);
+        decodeConfigs(R.drawable.grayscale_jpg, 128, 128, false, true);
+        decodeConfigs(R.drawable.grayscale_png, 128, 128, false, true);
     }
 
     @Test(expected=IllegalArgumentException.class)
@@ -812,8 +802,7 @@
         }
     }
 
-    private void decodeConfigs(int id, int width, int height, boolean hasAlpha, boolean isGray,
-            boolean hasColorTable) {
+    private void decodeConfigs(int id, int width, int height, boolean hasAlpha, boolean isGray) {
         Options opts = new BitmapFactory.Options();
         opts.inScaled = false;
         assertEquals(Config.ARGB_8888, opts.inPreferredConfig);
@@ -859,21 +848,15 @@
             compareBitmaps(reference, grayToARGB(alpha8), 0, true, true);
         }
 
-        // Setting inPreferredConfig to null selects the most natural color type for
-        // the encoded data.  If the image has a color table, this should be INDEX_8.
-        // If we decode to INDEX_8, the output bitmap will report that the Config is
-        // null.
+        // Setting inPreferredConfig to nullptr will cause the default Config to be
+        // selected, which in this case is ARGB_8888.
         opts.inPreferredConfig = null;
-        Bitmap index8 = BitmapFactory.decodeResource(mRes, id, opts);
-        assertNotNull(index8);
-        assertEquals(width, index8.getWidth());
-        assertEquals(height, index8.getHeight());
-        if (hasColorTable) {
-            assertEquals(null, index8.getConfig());
-            // Convert the INDEX_8 bitmap to ARGB_8888 and test that it is identical to
-            // the reference.
-            compareBitmaps(reference, index8.copy(Config.ARGB_8888, false), 0, true, true);
-        }
+        Bitmap defaultBitmap = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(defaultBitmap);
+        assertEquals(width, defaultBitmap.getWidth());
+        assertEquals(height, defaultBitmap.getHeight());
+        assertEquals(Config.ARGB_8888, defaultBitmap.getConfig());
+        compareBitmaps(reference, defaultBitmap, 0, true, true);
     }
 
     private static Bitmap grayToARGB(Bitmap gray) {
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java
index 42b493d..ad759bb 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java
@@ -92,7 +92,6 @@
         b = BitmapFactory.decodeResource(resources, R.drawable.bitmap_indexed, options);
         assertNull(b);
         assertEquals("image/gif", options.outMimeType);
-        assertEquals(null, options.outConfig);
 
         // Scaled, indexed bitmap
         options.inScaled = true;
diff --git a/tests/tests/graphics/src/android/graphics/cts/SyncTest.java b/tests/tests/graphics/src/android/graphics/cts/SyncTest.java
new file mode 100644
index 0000000..a82adfc
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/SyncTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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 android.graphics.cts;
+
+import static org.junit.Assert.assertEquals;
+import static android.opengl.EGL14.*;
+
+import android.opengl.EGL14;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSurface;
+import android.opengl.GLES20;
+import android.support.test.filters.SmallTest;
+
+import java.util.concurrent.CyclicBarrier;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+
+// This class contains tests for the Linux kernel sync file system, and the NDK interfaces for it
+// (android/sync.h). Unfortunately, the interfaces exposed by the kernel make it difficult to test
+// for a couple reasons:
+//
+// (a) There isn't a standard kernel interface for creating a fence/sync_file. Drivers can create
+//     them via driver-specific interfaces. Currently this means we have to use APIs like OpenGL ES
+//     or interact with the system compositor in order to generate fences. That makes tests larger
+//     and more complicated than they otherwise need to be.
+//
+//     This is further complicated by the fact that most of the time GPU work executes in the order
+//     it was submitted to the kernel; there isn't much out-of-order execution in practice. So
+//     detecting some kinds of bugs is difficult using only the GPU as an event source.
+//
+// (b) A core principal of sync files is that they cannot be created until the work that will
+//     signal them has been submitted to the kernel, and will complete without further action from
+//     userland. This means that it is impossible to reliably do something before a sync file has
+//     signaled.
+
+@SmallTest
+@RunWith(BlockJUnit4ClassRunner.class)
+public class SyncTest {
+
+    static {
+        System.loadLibrary("ctsgraphics_jni");
+    }
+
+    private static final String TAG = SyncTest.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private EGLDisplay mEglDisplay = EGL_NO_DISPLAY;
+    private EGLConfig mEglConfig = null;
+
+    @Before
+    public void setup() throws Throwable {
+        mEglDisplay = EGL14.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        if (mEglDisplay == EGL_NO_DISPLAY) {
+            throw new RuntimeException("no EGL display");
+        }
+        int[] major = new int[1];
+        int[] minor = new int[1];
+        if (!EGL14.eglInitialize(mEglDisplay, major, 0, minor, 0)) {
+            throw new RuntimeException("error in eglInitialize");
+        }
+
+        int[] numConfigs = new int[1];
+        EGLConfig[] configs = new EGLConfig[1];
+        if (!EGL14.eglChooseConfig(mEglDisplay,
+                new int[] {
+                    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                    EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+                    EGL_BUFFER_SIZE, 32,
+                    EGL_NONE},
+                0, configs, 0, 1, numConfigs, 0)) {
+            throw new RuntimeException("eglChooseConfig failed");
+        }
+        mEglConfig = configs[0];
+    }
+
+    @After
+    public void teardown() throws Throwable {
+        EGL14.eglTerminate(mEglDisplay);
+    }
+
+    @Test
+    public void testMergedSyncSignalOrder() {
+        // TODO
+    }
+
+    private static final int STATUS_UNSIGNALED = 0;
+    private static final int STATUS_SIGNALED = 1;
+    private static final int STATUS_ERROR = -1;
+    private static class SyncFileInfo {
+        String name;            // char name[32]
+        int status;             // __s32 status
+        long flags;             // __u32 flags
+        SyncFenceInfo[] fences; // __u32 num_fences; __u64 sync_fence_info
+    }
+    private static class SyncFenceInfo {
+        String name;            // char obj_name[32]
+        String driver_name;     // char driver_name[32]
+        int status;             // __s32 status
+        long flags;             // __u32 flags
+        long timestamp_ns;      // __u64 timestamp_ns
+    }
+
+    private static native boolean nSyncPoll(int[] fds, int[] status);
+    private static native int nSyncMerge(String name, int fd1, int fd2);
+    private static native SyncFileInfo nSyncFileInfo(int fd);
+    private static native void nSyncClose(int fd);
+}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
index 170d685..eddcecc 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
@@ -536,138 +536,4 @@
             resources.getDrawable(R.drawable.testimage).setAlpha(restoreAlpha);
         }
     }
-
-    private static final int[] DENSITY_VALUES = new int[] {
-            160, 80, 320
-    };
-
-    private static final int[] DENSITY_IMAGES = new int[] {
-            R.drawable.bitmap_density,
-            R.drawable.bitmap_shader_density,
-            R.drawable.bitmap_shader_am_density,
-    };
-
-    @Test
-    public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final Resources res = mContext.getResources();
-        final int densityDpi = res.getConfiguration().densityDpi;
-        try {
-            for (int i = 0; i < DENSITY_IMAGES.length; i++) {
-                verifyPreloadDensityInner(res, DENSITY_IMAGES[i], DENSITY_VALUES);
-            }
-        } finally {
-            DrawableTestUtils.setResourcesDensity(res, densityDpi);
-        }
-    }
-
-    private void verifyPreloadDensityInner(Resources res, int sourceResId, int[] densities)
-            throws XmlPullParserException, IOException {
-        final Rect tempPadding = new Rect();
-
-        // Capture initial state at preload density.
-        final int preloadDensityDpi = densities[0];
-        DrawableTestUtils.setResourcesDensity(res, preloadDensityDpi);
-
-        final XmlResourceParser parser = DrawableTestUtils.getResourceParser(res, sourceResId);
-        final BitmapDrawable preloadedDrawable = new BitmapDrawable();
-        preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
-
-        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
-        final int origWidth = preloadedDrawable.getIntrinsicWidth();
-        final int origHeight = preloadedDrawable.getIntrinsicHeight();
-        assertFalse(preloadedDrawable.getPadding(tempPadding));
-
-        compareOrSave(preloadedDrawable, preloadDensityDpi, sourceResId);
-
-        for (int i = 1; i < densities.length; i++) {
-            final int scaledDensityDpi = densities[i];
-            final float scale = scaledDensityDpi / (float) preloadDensityDpi;
-            DrawableTestUtils.setResourcesDensity(res, scaledDensityDpi);
-
-            final BitmapDrawable scaledDrawable =
-                    (BitmapDrawable) preloadedConstantState.newDrawable(res);
-            scaledDrawable.setLayoutDirection(LayoutDirection.RTL);
-
-            // Sizes are rounded.
-            assertEquals(Math.round(origWidth * scale), scaledDrawable.getIntrinsicWidth());
-            assertEquals(Math.round(origHeight * scale), scaledDrawable.getIntrinsicHeight());
-
-            // Bitmaps have no padding.
-            assertFalse(scaledDrawable.getPadding(tempPadding));
-
-            compareOrSave(scaledDrawable, scaledDensityDpi, sourceResId);
-
-            // Ensure theme density is applied correctly. Unlike most
-            // drawables, we don't have any loss of accuracy because density
-            // changes are re-computed from the source every time.
-            DrawableTestUtils.setResourcesDensity(res, preloadDensityDpi);
-
-            final Theme t = res.newTheme();
-            scaledDrawable.applyTheme(t);
-            assertEquals(origWidth, scaledDrawable.getIntrinsicWidth());
-            assertEquals(origHeight, scaledDrawable.getIntrinsicHeight());
-            assertFalse(scaledDrawable.getPadding(tempPadding));
-        }
-    }
-
-    private void compareOrSave(Drawable dr, int densityDpi, int sourceResId) {
-        final int width = dr.getIntrinsicWidth();
-        final int height = dr.getIntrinsicHeight();
-        final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        bitmap.setDensity(0);
-
-        final Canvas canvas = new Canvas(bitmap);
-        dr.setBounds(0, 0, width, height);
-        dr.draw(canvas);
-
-        if (DBG_DUMP_PNG) {
-            saveGoldenImage(bitmap, sourceResId, densityDpi);
-        } else {
-            final int goldenResId = getGoldenImageResId(sourceResId, densityDpi);
-            final Bitmap golden = BitmapFactory.decodeResource(
-                    mContext.getResources(), goldenResId);
-            DrawableTestUtils.compareImages(densityDpi + " dpi", golden, bitmap,
-                    PIXEL_ERROR_THRESHOLD, PIXEL_ERROR_COUNT_THRESHOLD, 0 /* tolerance */);
-        }
-    }
-
-    private int getGoldenImageResId(int sourceResId, int densityDpi) {
-        final String name = getGoldenImageName(sourceResId, densityDpi);
-        return mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
-    }
-
-    private String getGoldenImageName(int sourceResId, int densityDpi) {
-        return mContext.getResources().getResourceEntryName(sourceResId) + "_golden_" + densityDpi;
-    }
-
-    private void saveGoldenImage(Bitmap bitmap, int sourceResId, int densityDpi) {
-        // Save the image to the disk.
-        FileOutputStream out = null;
-
-        try {
-            final File outputFolder = new File("/sdcard/temp/");
-            if (!outputFolder.exists()) {
-                outputFolder.mkdir();
-            }
-
-            final String goldenFilename = getGoldenImageName(sourceResId, densityDpi) + ".png";
-            final File goldenFile = new File(outputFolder, goldenFilename);
-            if (!goldenFile.exists()) {
-                goldenFile.createNewFile();
-            }
-
-            out = new FileOutputStream(goldenFile, false);
-            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            if (out != null) {
-                try {
-                    out.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
 }
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 68e7e50..3adf811 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MULTILIB := both
 
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 4a65c44..5b80a37 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -34,7 +34,7 @@
 	android-icu4j-tests
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsIcuTestCases
 
diff --git a/tests/tests/incident/Android.mk b/tests/tests/incident/Android.mk
index bb83dda..1309c99 100644
--- a/tests/tests/incident/Android.mk
+++ b/tests/tests/incident/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsIncidentTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 #LOCAL_SDK_VERSION := current
 LOCAL_JAVA_LIBRARIES += android.test.runner
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index 38111fc..1f332b9 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
diff --git a/tests/tests/jni/libjnitest/Android.mk b/tests/tests/jni/libjnitest/Android.mk
index 7140de4..0703722 100644
--- a/tests/tests/jni/libjnitest/Android.mk
+++ b/tests/tests/jni/libjnitest/Android.mk
@@ -42,4 +42,6 @@
 LOCAL_SDK_VERSION := 23
 LOCAL_NDK_STL_VARIANT := c++_static
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index 21578d4..ea24954 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_LIBRARIES := bouncycastle
 
diff --git a/tests/tests/libcorefileio/Android.mk b/tests/tests/libcorefileio/Android.mk
index 066d727..cfd9775 100644
--- a/tests/tests/libcorefileio/Android.mk
+++ b/tests/tests/libcorefileio/Android.mk
@@ -28,6 +28,6 @@
 LOCAL_PACKAGE_NAME := CtsLibcoreFileIOTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/libcorelegacy22/Android.mk b/tests/tests/libcorelegacy22/Android.mk
index 2788337..d2468c3 100644
--- a/tests/tests/libcorelegacy22/Android.mk
+++ b/tests/tests/libcorelegacy22/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_SDK_VERSION := 22
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/location/Android.mk b/tests/tests/location/Android.mk
index 3c98287..acbf640 100644
--- a/tests/tests/location/Android.mk
+++ b/tests/tests/location/Android.mk
@@ -45,7 +45,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
diff --git a/tests/tests/location2/Android.mk b/tests/tests/location2/Android.mk
index de01ba8..5b9f327 100644
--- a/tests/tests/location2/Android.mk
+++ b/tests/tests/location2/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner junit legacy-android-test
 
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index 9db91bb..e03eb76 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -77,7 +77,7 @@
 LOCAL_JAVA_LIBRARIES += android.test.runner org.apache.http.legacy
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
index b98a6af..571cec4 100644
--- a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -59,9 +59,9 @@
 static const size_t kPlayTimeSeconds = 30;
 static const size_t kUuidSize = 16;
 
-static const uint8_t kWidevineUuid[kUuidSize] = {
-    0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce,
-    0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed
+static const uint8_t kClearKeyUuid[kUuidSize] = {
+    0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
+    0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b
 };
 
 // The test content is not packaged with clearkey UUID,
@@ -77,8 +77,8 @@
     // number of key ids
     0x00, 0x00, 0x00, 0x01,
     // key id
-    0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87,
-    0x7e, 0x57, 0xd0, 0x0d, 0x1e, 0xd0, 0x0d, 0x1e,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
     // size of data, must be zero
     0x00, 0x00, 0x00, 0x00
 };
@@ -86,23 +86,23 @@
 static const uint8_t kKeyRequestData[] = {
     0x7b, 0x22, 0x6b, 0x69, 0x64,
     0x73, 0x22, 0x3a, 0x5b, 0x22,
-    0x59, 0x41, 0x59, 0x65, 0x41,
-    0x58, 0x35, 0x48, 0x66, 0x6f,
-    0x64, 0x2b, 0x56, 0x39, 0x41,
-    0x4e, 0x48, 0x74, 0x41, 0x4e,
-    0x48, 0x67, 0x22, 0x5d, 0x2c,
+    0x4d, 0x44, 0x41, 0x77, 0x4d,
+    0x44, 0x41, 0x77, 0x4d, 0x44,
+    0x41, 0x77, 0x4d, 0x44, 0x41,
+    0x77, 0x4d, 0x44, 0x41, 0x77,
+    0x4d, 0x41, 0x22, 0x5d, 0x2c,
     0x22, 0x74, 0x79, 0x70, 0x65,
     0x22, 0x3a, 0x22, 0x74, 0x65,
     0x6d, 0x70, 0x6f, 0x72, 0x61,
-    0x72, 0x79, 0x22, 0x7d,
+    0x72, 0x79, 0x22, 0x7d
 };
 
 static const size_t kKeyRequestSize = sizeof(kKeyRequestData);
 
 // base 64 encoded JSON response string, must not contain padding character '='
 static const char kResponse[] = "{\"keys\":[{\"kty\":\"oct\"," \
-        "\"kid\":\"YAYeAX5Hfod+V9ANHtANHg\",\"k\":" \
-        "\"GoogleTestKeyBase64ggg\"}]}";
+        "\"kid\":\"MDAwMDAwMDAwMDAwMDAwMA\",\"k\":" \
+        "\"Pwoz80CYueIrwHjgobXoVA\"}]}";
 
 static bool isUuidSizeValid(Uuid uuid) {
     return (uuid.size() == kUuidSize);
@@ -246,17 +246,12 @@
     for (size_t i = 0; i < psshInfo->numentries; i++) {
         PsshEntry *entry = &psshInfo->entries[i];
 
-        // We do not have clearkey content that contains ClearKey UUID in the
-        // pssh box. So we have to test if it has Widevine UUID instead.
-        // TODO: Replace kWidevineUuid with uuid when test content contains
-        // ClearKey UUID.
-        if (0 == memcmp(entry->uuid, kWidevineUuid, sizeof(entry->uuid))) {
-            aMediaObjects.setCrypto(
-                AMediaCrypto_new(entry->uuid, entry->data, entry->datalen));
-            if (aMediaObjects.getCrypto()) {
+        if (0 == memcmp(entry->uuid, kClearKeyUuid, sizeof(entry->uuid))) {
+            aMediaObjects.setDrm(AMediaDrm_createByUUID(&juuid[0]));
+            if (aMediaObjects.getDrm()) {
                 testResult = JNI_TRUE;
             } else {
-                ALOGE("Failed to create media crypto=%zd", i);
+                ALOGE("Failed to create media drm=%zd", i);
                 testResult = JNI_FALSE;
             }
             break;
@@ -293,6 +288,7 @@
         AMediaCodec** codec) {
     size_t numTracks = AMediaExtractor_getTrackCount(
         const_cast<AMediaExtractor*>(extractor));
+
     AMediaFormat* trackFormat = NULL;
     for (size_t i = 0; i < numTracks; ++i) {
         trackFormat = AMediaExtractor_getTrackFormat(
@@ -305,6 +301,7 @@
             if (!AMediaFormat_getString(
                 trackFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
                 ALOGE("no mime type");
+
                 AMediaFormat_delete(trackFormat);
                 return;
             } else if (isAudio(mime) || isVideo(mime)) {
@@ -350,6 +347,7 @@
 
         AMediaCodecCryptoInfo *cryptoInfo =
             AMediaExtractor_getSampleCryptoInfo(extractor);
+
         if (cryptoInfo) {
             status = AMediaCodec_queueSecureInputBuffer(
                 codec, bufferIndex, 0, cryptoInfo,
@@ -420,6 +418,7 @@
     }
 
     addTracks(audioExtractor, NULL, NULL, &audioCodec);
+
     addTracks(videoExtractor, crypto, window, &videoCodec);
 
     bool sawAudioInputEos = false;
@@ -615,7 +614,7 @@
             int count = 0;
             while (!gGotVendorDefinedEvent && count++ < 5) {
                // Prevents race condition when the event arrives late
-               usleep(1000);
+               usleep(2000);
             }
             if (!gGotVendorDefinedEvent) {
                 ALOGE("Event listener did not receive the expected event.");
diff --git a/tests/tests/media/res/raw/gb18030_utf8_mixed_1.mp3 b/tests/tests/media/res/raw/gb18030_utf8_mixed_1.mp3
new file mode 100644
index 0000000..af2c7ac
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_utf8_mixed_1.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_utf8_mixed_2.mp3 b/tests/tests/media/res/raw/gb18030_utf8_mixed_2.mp3
new file mode 100644
index 0000000..d1c88fe
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_utf8_mixed_2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_utf8_mixed_3.mp3 b/tests/tests/media/res/raw/gb18030_utf8_mixed_3.mp3
new file mode 100644
index 0000000..ddae12f
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_utf8_mixed_3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/iso88591_utf8_mixed_1.mp3 b/tests/tests/media/res/raw/iso88591_utf8_mixed_1.mp3
new file mode 100644
index 0000000..78bad13
--- /dev/null
+++ b/tests/tests/media/res/raw/iso88591_utf8_mixed_1.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/iso88591_utf8_mixed_2.mp3 b/tests/tests/media/res/raw/iso88591_utf8_mixed_2.mp3
new file mode 100644
index 0000000..c7d8429
--- /dev/null
+++ b/tests/tests/media/res/raw/iso88591_utf8_mixed_2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/iso88591_utf8_mixed_3.mp3 b/tests/tests/media/res/raw/iso88591_utf8_mixed_3.mp3
new file mode 100644
index 0000000..c8d4afa
--- /dev/null
+++ b/tests/tests/media/res/raw/iso88591_utf8_mixed_3.mp3
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
index 61edbba..068087d 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
@@ -20,6 +20,7 @@
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
 import android.media.AudioRecord;
 import android.media.AudioRecordingConfiguration;
 import android.media.MediaRecorder;
@@ -31,6 +32,7 @@
 
 import com.android.compatibility.common.util.CtsAndroidTestCase;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -127,6 +129,9 @@
                 verifyAudioConfig(TEST_AUDIO_SOURCE, mAudioRecord.getAudioSessionId(),
                         mAudioRecord.getFormat(), mAudioRecord.getRoutedDevice(), configs));
 
+        // testing public API here: verify no system-privileged info is exposed through reflection
+        verifyPrivilegedInfoIsSafe(configs.get(0));
+
         // stopping recording: verify there are less active record configurations
         mAudioRecord.stop();
         Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
@@ -181,6 +186,10 @@
                     testDevice, callback.mConfigs);
             assertTrue("Expected record configuration was not found", match);
 
+            // testing public API here: verify no system-privileged info is exposed through
+            // reflection
+            verifyPrivilegedInfoIsSafe(callback.mConfigs.get(0));
+
             // stopping recording: callback is called with no match
             callback.reset();
             mAudioRecord.stop();
@@ -303,4 +312,20 @@
         return getContext().getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_MICROPHONE);
     }
+
+    private static void verifyPrivilegedInfoIsSafe(AudioRecordingConfiguration config) {
+        // verify "privileged" fields aren't available through reflection
+        final Class<?> confClass = config.getClass();
+        try {
+            final Method getClientUidMethod = confClass.getDeclaredMethod("getClientUid");
+            final Method getClientPackageName = confClass.getDeclaredMethod("getClientPackageName");
+            Integer uid = (Integer) getClientUidMethod.invoke(config, null);
+            assertEquals("client uid isn't protected", -1 /*expected*/, uid.intValue());
+            String name = (String) getClientPackageName.invoke(config, null);
+            assertNotNull("client package name is null", name);
+            assertEquals("client package name isn't protected", 0 /*expected*/, name.length());
+        } catch (Exception e) {
+            fail("Exception thrown during reflection on config privileged fields" + e);
+        }
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index 9b5f001..f0b303b 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -21,6 +21,7 @@
 import android.graphics.BitmapFactory;
 import android.media.ExifInterface;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.system.ErrnoException;
@@ -70,7 +71,7 @@
             ExifInterface.TAG_MAKE,
             ExifInterface.TAG_MODEL,
             ExifInterface.TAG_F_NUMBER,
-            ExifInterface.TAG_DATETIME,
+            ExifInterface.TAG_DATETIME_ORIGINAL,
             ExifInterface.TAG_EXPOSURE_TIME,
             ExifInterface.TAG_FLASH,
             ExifInterface.TAG_FOCAL_LENGTH,
@@ -107,7 +108,7 @@
         public final String make;
         public final String model;
         public final float aperture;
-        public final String datetime;
+        public final String dateTimeOriginal;
         public final float exposureTime;
         public final float flash;
         public final String focalLength;
@@ -153,7 +154,7 @@
             make = getString(typedArray, index++);
             model = getString(typedArray, index++);
             aperture = typedArray.getFloat(index++, 0f);
-            datetime = getString(typedArray, index++);
+            dateTimeOriginal = getString(typedArray, index++);
             exposureTime = typedArray.getFloat(index++, 0f);
             flash = typedArray.getFloat(index++, 0f);
             focalLength = getString(typedArray, index++);
@@ -273,7 +274,8 @@
         assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
         assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
         assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
-        assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
+        assertStringTag(exifInterface, ExifInterface.TAG_DATETIME_ORIGINAL,
+                expectedValue.dateTimeOriginal);
         assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
         assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
         assertStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
@@ -478,4 +480,34 @@
     public void testReadExifDataFromSamsungNX3000Srw() throws Throwable {
         testExifInterfaceForRaw(SAMSUNG_NX3000_SRW, R.array.samsung_nx3000_srw);
     }
+
+    public void testSetDateTime() throws IOException {
+        final String dateTimeValue = "2017:02:02 22:22:22";
+        final String dateTimeOriginalValue = "2017:01:01 11:11:11";
+
+        File srcFile = new File(Environment.getExternalStorageDirectory(),
+                EXTERNAL_BASE_DIRECTORY + EXIF_BYTE_ORDER_II_JPEG);
+        File imageFile = new File(Environment.getExternalStorageDirectory(),
+                EXTERNAL_BASE_DIRECTORY + EXIF_BYTE_ORDER_II_JPEG + "_copied");
+
+        FileUtils.copyFileOrThrow(srcFile, imageFile);
+        ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
+        exif.setAttribute(ExifInterface.TAG_DATETIME, dateTimeValue);
+        exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTimeOriginalValue);
+        exif.saveAttributes();
+
+        // Check that the DATETIME value is not overwritten by DATETIME_ORIGINAL's value.
+        exif = new ExifInterface(imageFile.getAbsolutePath());
+        assertEquals(dateTimeValue, exif.getAttribute(ExifInterface.TAG_DATETIME));
+        assertEquals(dateTimeOriginalValue, exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL));
+
+        // Now remove the DATETIME value.
+        exif.setAttribute(ExifInterface.TAG_DATETIME, null);
+        exif.saveAttributes();
+
+        // When the DATETIME has no value, then it should be set to DATETIME_ORIGINAL's value.
+        exif = new ExifInterface(imageFile.getAbsolutePath());
+        assertEquals(dateTimeOriginalValue, exif.getAttribute(ExifInterface.TAG_DATETIME));
+        imageFile.delete();
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java
index 6f5a355..8eb82da 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java
@@ -779,7 +779,7 @@
                     initData = CLEARKEY_PSSH;
                     Log.d(TAG, "setupDrm: CLEARKEY scheme not found in PSSH. Using default data.");
                 }
-                Log.d(TAG, "setupDrm: initData[" + drmScheme + "]: " + initData);
+                Log.d(TAG, "setupDrm: initData[" + drmScheme + "]: " + Arrays.toString(initData));
 
                 // diverging from GTS
                 mime = "cenc";
@@ -818,7 +818,7 @@
             byte[] keySetId = mMediaPlayer.provideKeyResponse(
                     (keyType == MediaDrm.KEY_TYPE_RELEASE) ? mKeySetId : null,
                     response);
-            Log.d(TAG, "setupDrm: provideKeyResponse -> " + keySetId);
+            Log.d(TAG, "setupDrm: provideKeyResponse -> " + Arrays.toString(keySetId));
             // storing offline key for a later restore
             mKeySetId = (keyType == MediaDrm.KEY_TYPE_OFFLINE) ? keySetId : null;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index 3a12e3b..137b7cf 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -470,7 +470,20 @@
             new MediaScanEntry(R.raw.iso88591_13,
                     new String[] {"Michael Bublé", "Crazy Love", "Michael Bublé", "Haven't Met You Yet", null}),
             new MediaScanEntry(R.raw.utf16_1,
-                    new String[] {"Shakira", "Latin Mix USA", "Shakira", "Estoy Aquí", null})
+                    new String[] {"Shakira", "Latin Mix USA", "Shakira", "Estoy Aquí", null}),
+            // Tags are encoded in different charsets.
+            new MediaScanEntry(R.raw.iso88591_utf8_mixed_1,
+                    new String[] {"刘昊霖/kidult.", "鱼干铺里", "刘昊霖/kidult.", "Colin Wine's Mailbox", null}),
+            new MediaScanEntry(R.raw.iso88591_utf8_mixed_2,
+                    new String[] {"冰块先生/郭美孜", "hey jude", "冰块先生/郭美孜", "Hey Jude", null}),
+            new MediaScanEntry(R.raw.iso88591_utf8_mixed_3,
+                    new String[] {"Toy王奕/Tizzy T/满舒克", "1993", "Toy王奕/Tizzy T/满舒克", "Me&Ma Bros", null}),
+            new MediaScanEntry(R.raw.gb18030_utf8_mixed_1,
+                    new String[] {"张国荣", "钟情张国荣", null, "左右手", null}),
+            new MediaScanEntry(R.raw.gb18030_utf8_mixed_2,
+                    new String[] {"纵贯线", "Live in Taipei 出发\\/终点站", null, "皇后大道东(Live)", null}),
+            new MediaScanEntry(R.raw.gb18030_utf8_mixed_3,
+                    new String[] {"谭咏麟", "二十年白金畅销金曲全记录", null, "知心当玩偶", null})
     };
 
     public void testEncodingDetection() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
index 16201b2..4a7b7af 100644
--- a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
@@ -45,11 +45,12 @@
     private static final String ISO_BMFF_VIDEO_MIME_TYPE = "video/avc";
     private static final String ISO_BMFF_AUDIO_MIME_TYPE = "audio/avc";
     private static final Uri CENC_AUDIO_URL = Uri.parse(
-        "http://yt-dash-mse-test.commondatastorage.googleapis.com/media/" +
-        "car_cenc-20120827-8c.mp4");
+        "https://storage.googleapis.com/wvmedia/clear/h264/llama/" +
+        "llama_aac_audio.mp4");
+
     private static final Uri CENC_CLEARKEY_VIDEO_URL = Uri.parse(
-        "http://yt-dash-mse-test.commondatastorage.googleapis.com/media/" +
-        "car_cenc-20120827-88.mp4");
+        "https://storage.googleapis.com/wvmedia/clearkey/" +
+        "llama_h264_main_720p_8000.mp4");
 
     private static final int UUID_BYTE_SIZE = 16;
     private static final UUID CLEARKEY_SCHEME_UUID =
@@ -171,7 +172,7 @@
         }
         connectionStatus.testConnection(videoUrl);
 
-        if (!MediaUtils.checkCodecsForPath(mContext, videoUrl.getPath())) {
+        if (!MediaUtils.checkCodecsForPath(mContext, videoUrl.toString())) {
             Log.i(TAG, "Device does not support " +
                   videoWidth + "x" + videoHeight + " resolution for " + mimeType);
             return;  // skip
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerTest.java b/tests/tests/media/src/android/media/cts/ResourceManagerTest.java
index 5f16bc5..b541a97 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/ResourceManagerTest.java
@@ -17,8 +17,12 @@
 package android.media.cts;
 
 import android.os.Bundle;
+import android.platform.test.annotations.RequiresDevice;
+import android.support.test.filters.SmallTest;
 import android.test.ActivityInstrumentationTestCase2;
 
+@SmallTest
+@RequiresDevice
 public class ResourceManagerTest
         extends ActivityInstrumentationTestCase2<ResourceManagerStubActivity> {
 
diff --git a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java b/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
index 9f90a75..72ec8a9 100644
--- a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
+++ b/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
@@ -62,6 +62,14 @@
     }
 
     @Override
+    public void onDestroy() {
+        super.onDestroy();
+        sSession.release();
+        sInstance = null;
+        sSession = null;
+    }
+
+    @Override
     public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
         mExtras = new Bundle();
         mExtras.putString(EXTRAS_KEY, EXTRAS_VALUE);
diff --git a/tests/tests/media/src/android/media/cts/Utils.java b/tests/tests/media/src/android/media/cts/Utils.java
index 33cc1b7..211aa4e 100644
--- a/tests/tests/media/src/android/media/cts/Utils.java
+++ b/tests/tests/media/src/android/media/cts/Utils.java
@@ -17,6 +17,7 @@
 package android.media.cts;
 
 import android.app.Instrumentation;
+import android.app.NotificationManager;
 import android.app.UiAutomation;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -88,57 +89,10 @@
     protected static void toggleNotificationPolicyAccess(String packageName,
             Instrumentation instrumentation, boolean on) throws IOException {
 
-        // Read the setting listing the package allowed to manage notification policy configuration
-        String alreadyEnabledServices = querryNotificationPolicyAccessPakages(instrumentation);
-
-        // The property is a list of : separated package
-        List<String> enabledServices = Lists.newArrayList(alreadyEnabledServices.split(":"));
-
-        // Actually add or remove the package from the list
-        if (on) {
-            // Only add the package if it is not already in the list
-            if (!enabledServices.contains(packageName)) {
-                enabledServices.add(packageName);
-                setNotificationPolicyAccessPackages(enabledServices, instrumentation);
-            }
-        } else {
-            // Remove all instance of the package in the list
-            if (enabledServices.removeIf(packageName::equals)) {
-                // Only update the settings if there was a change
-                setNotificationPolicyAccessPackages(enabledServices, instrumentation);
-            }
-        }
-    }
-
-    /** Read the setting listing the package allowed to manage notification policy configuration */
-    private static String querryNotificationPolicyAccessPakages(Instrumentation instrumentation) {
-        ContentResolver cr = instrumentation.getContext().getContentResolver();
-        String enabledService = Settings.Secure.getString(
-                cr,Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
-
-        // A non existing property is equivalent to no package listed
-        if (enabledService == null) {
-            enabledService = "";
-        }
-        return enabledService;
-    }
-
-    private static void setNotificationPolicyAccessPackages(final List<String> enabledServicesList,
-            final Instrumentation instrumentation) throws IOException {
-        // Format the list back to a string
-        String enabledServices = String.join(":", enabledServicesList);
-
-        // If the list is empty, remove the property by setting it to null
-        String enabledServicesStrOrNull = enabledServices.isEmpty() ? "null" : enabledServices;
-
-        // Write back the property to the settings database
-        String command = "settings --user cur put secure "
-                + Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES + "  "
-                + enabledServicesStrOrNull;
+        String command = " cmd notification " + (on ? "allow_dnd " : "disallow_dnd ") + packageName;
 
         // Get permission to enable accessibility
         UiAutomation uiAutomation = instrumentation.getUiAutomation();
-
         // Execute command
         try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
             Assert.assertNotNull("Failed to execute shell command: " + command, fd);
@@ -153,11 +107,10 @@
             uiAutomation.destroy();
         }
 
-        // Read the settings again to make sure it is updated
-        String nowEnabledServices = querryNotificationPolicyAccessPakages(instrumentation);
-        Assert.assertEquals("Wrote setting should be the same as the read one",
-                enabledServices, nowEnabledServices);
-
+        NotificationManager nm = (NotificationManager) instrumentation.getContext()
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+        Assert.assertEquals("Wrote setting should be the same as the read one", on,
+                nm.isNotificationPolicyAccessGranted());
     }
 
     /**
diff --git a/tests/tests/mediastress/Android.mk b/tests/tests/mediastress/Android.mk
index 55e7a3a..0213c00 100644
--- a/tests/tests/mediastress/Android.mk
+++ b/tests/tests/mediastress/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
diff --git a/tests/tests/mediastress/jni/Android.mk b/tests/tests/mediastress/jni/Android.mk
index 164e302..6756bc3 100644
--- a/tests/tests/mediastress/jni/Android.mk
+++ b/tests/tests/mediastress/jni/Android.mk
@@ -29,4 +29,6 @@
 LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog libOpenMAXAL
 LOCAL_CXX_STL := libc++_static
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/mediastress/preconditions/Android.mk b/tests/tests/mediastress/preconditions/Android.mk
index c6c1cf2..c88a948 100644
--- a/tests/tests/mediastress/preconditions/Android.mk
+++ b/tests/tests/mediastress/preconditions/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MODULE := compatibility-host-media-preconditions
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/mediastress/preconditions/app/Android.mk b/tests/tests/mediastress/preconditions/app/Android.mk
index 8630ac1..9d44f8c 100644
--- a/tests/tests/mediastress/preconditions/app/Android.mk
+++ b/tests/tests/mediastress/preconditions/app/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsMediaPreparerApp
 
diff --git a/tests/tests/midi/Android.mk b/tests/tests/midi/Android.mk
index 4192e5d..cefe3cc 100755
--- a/tests/tests/midi/Android.mk
+++ b/tests/tests/midi/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
diff --git a/tests/tests/multiuser/Android.mk b/tests/tests/multiuser/Android.mk
index e85fed2..992b5fe 100644
--- a/tests/tests/multiuser/Android.mk
+++ b/tests/tests/multiuser/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/nativehardware/Android.mk b/tests/tests/nativehardware/Android.mk
index 065f5d2..38688be 100644
--- a/tests/tests/nativehardware/Android.mk
+++ b/tests/tests/nativehardware/Android.mk
@@ -71,7 +71,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
diff --git a/tests/tests/nativemedia/aaudio/Android.mk b/tests/tests/nativemedia/aaudio/Android.mk
index 983a894..66acd71 100644
--- a/tests/tests/nativemedia/aaudio/Android.mk
+++ b/tests/tests/nativemedia/aaudio/Android.mk
@@ -40,7 +40,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.nativemedia.aaudio
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CFLAGS := -Werror -Wall
 
diff --git a/tests/tests/nativemedia/sl/Android.mk b/tests/tests/nativemedia/sl/Android.mk
index 2e99354..7d0edeb 100644
--- a/tests/tests/nativemedia/sl/Android.mk
+++ b/tests/tests/nativemedia/sl/Android.mk
@@ -42,7 +42,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.nativemedia.sl
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CFLAGS := -Werror -Wall
 
diff --git a/tests/tests/nativemedia/xa/Android.mk b/tests/tests/nativemedia/xa/Android.mk
index 1a9fe43..c11c10e 100644
--- a/tests/tests/nativemedia/xa/Android.mk
+++ b/tests/tests/nativemedia/xa/Android.mk
@@ -41,6 +41,6 @@
 LOCAL_CTS_TEST_PACKAGE := android.nativemedia.xa
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/tests/tests/ndef/Android.mk b/tests/tests/ndef/Android.mk
index 47f45c9..c355fa0 100644
--- a/tests/tests/ndef/Android.mk
+++ b/tests/tests/ndef/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index 3493ccb..4aeab38 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -47,7 +47,7 @@
 #LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/net/appForApi23/Android.mk b/tests/tests/net/appForApi23/Android.mk
index ea99684..54b60a0 100644
--- a/tests/tests/net/appForApi23/Android.mk
+++ b/tests/tests/net/appForApi23/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_SDK_VERSION := 23
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/net/jni/Android.mk b/tests/tests/net/jni/Android.mk
index 0ec8d28..887e95e 100644
--- a/tests/tests/net/jni/Android.mk
+++ b/tests/tests/net/jni/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_SHARED_LIBRARIES := libnativehelper_compat_libc++ liblog
 LOCAL_CXX_STL := libc++_static
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/tests/tests/net/native/qtaguid/Android.mk b/tests/tests/net/native/qtaguid/Android.mk
index b3eb28b..6c92b5c 100644
--- a/tests/tests/net/native/qtaguid/Android.mk
+++ b/tests/tests/net/native/qtaguid/Android.mk
@@ -36,7 +36,7 @@
 
 LOCAL_CTS_TEST_PACKAGE := android.net.native
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 
 LOCAL_CFLAGS := -Werror -Wall
 
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
index c206b76..4c68423 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_INSTRUMENTATION_FOR := CtsNetSecPolicyUsesCleartextTrafficFalse
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
index ab95129..584afd2 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_INSTRUMENTATION_FOR := CtsNetSecPolicyUsesCleartextTrafficTrue
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
index 4e80528..9a613e7 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_INSTRUMENTATION_FOR := CtsNetSecPolicyUsesCleartextTrafficUnspecified
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
index d2ddb27..10018ce 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
index 716fecf..161dbd3 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
index 928b95d..927374c 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
index 4a55d81..aa0eefd 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
index 22ec6c7..be9174e 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
index f6be2b5..84e72b0 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
@@ -32,7 +32,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
index cbfd091..4764cab 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
index 2ae8d6c..5448f34 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
index e99d5c4..924f393 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
@@ -32,7 +32,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/opengl/Android.mk b/tests/tests/opengl/Android.mk
index 5558379..d623932 100644
--- a/tests/tests/opengl/Android.mk
+++ b/tests/tests/opengl/Android.mk
@@ -37,7 +37,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/opengl/libopengltest/Android.mk b/tests/tests/opengl/libopengltest/Android.mk
index afa94dc..f05fd8c 100755
--- a/tests/tests/opengl/libopengltest/Android.mk
+++ b/tests/tests/opengl/libopengltest/Android.mk
@@ -39,6 +39,9 @@
 LOCAL_CXX_STL := libc++_static
 
 LOCAL_SHARED_LIBRARIES := libGLESv2 liblog
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
 
 
diff --git a/tests/tests/opengl/libopengltest/gl2_jni_libone.cpp b/tests/tests/opengl/libopengltest/gl2_jni_libone.cpp
index fe49b1b..a511f9a 100755
--- a/tests/tests/opengl/libopengltest/gl2_jni_libone.cpp
+++ b/tests/tests/opengl/libopengltest/gl2_jni_libone.cpp
@@ -135,7 +135,7 @@
         jclass obj, jint pCategory, jint pSubCategory, jfloatArray color)
 {
     LOGI("Inside draw %d %d", pCategory, pSubCategory);
-    jfloatArray result;
+    jfloatArray result = nullptr;
     if(pCategory == 3){
         if(pSubCategory == 1){
             result = env->NewFloatArray(4);
@@ -143,8 +143,8 @@
             jfloat *lColor =  env->GetFloatArrayElements(color,0);
 
             float * actualColor = drawColorOne(lColor);
-            for( int i= 0; i < sizeof(actualColor); i++) {
-                LOGI("actualColor[%d] ; %f", i, actualColor[i]);
+            for(unsigned i = 0; i < sizeof(actualColor); i++) {
+                LOGI("actualColor[%u] ; %f", i, actualColor[i]);
             }
             env->SetFloatArrayRegion(result, 0, 4, actualColor);
         }
diff --git a/tests/tests/opengl/src/android/opengl/cts/CompressedTextureCtsActivity.java b/tests/tests/opengl/src/android/opengl/cts/CompressedTextureCtsActivity.java
index 15a7074..ed86051 100644
--- a/tests/tests/opengl/src/android/opengl/cts/CompressedTextureCtsActivity.java
+++ b/tests/tests/opengl/src/android/opengl/cts/CompressedTextureCtsActivity.java
@@ -63,6 +63,12 @@
     }
 
     @Override
+    protected void onPause() {
+        mCompressedTextureView.onPause();
+        super.onPause();
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
         mCompressedTextureView.onResume();
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionCtsActivity.java b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionCtsActivity.java
index 8a85555..dd89895 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionCtsActivity.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionCtsActivity.java
@@ -54,6 +54,8 @@
     /** Latch that is unlocked when the activity is done finding the version. */
     private CountDownLatch mSurfaceCreatedLatch = new CountDownLatch(1);
 
+    private GLSurfaceView mView;
+
     public static Intent createIntent(int eglContextClientVersion) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.putExtra(EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion);
@@ -64,16 +66,22 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        GLSurfaceView view = new GLSurfaceView(this);
+        mView = new GLSurfaceView(this);
 
         Intent intent = getIntent();
         int eglContextClientVersion = intent.getIntExtra(EGL_CONTEXT_CLIENT_VERSION, -1);
         if (eglContextClientVersion > 0) {
-            view.setEGLContextClientVersion(eglContextClientVersion);
+            mView.setEGLContextClientVersion(eglContextClientVersion);
         }
 
-        view.setRenderer(new Renderer());
-        setContentView(view);
+        mView.setRenderer(new Renderer());
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onPause() {
+        mView.onPause();
+        super.onPause();
     }
 
     public String getVersionString() throws InterruptedException {
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
index c290dac..4225de0 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -197,6 +197,41 @@
         }
     }
 
+    @Test
+    public void testRequiredEglExtensions() {
+        // See CDD section 7.1.4
+        final String requiredEglList[] = {
+            "EGL_KHR_image",
+            "EGL_KHR_image_base",
+            "EGL_ANDROID_image_native_buffer",
+            "EGL_ANDROID_get_native_client_buffer",
+            "EGL_KHR_wait_sync",
+            "EGL_KHR_get_all_proc_addresses",
+            "EGL_ANDROID_presentation_time",
+            "EGL_KHR_swap_buffers_with_damage"
+        };
+
+        EGL10 egl = (EGL10) EGLContext.getEGL();
+        EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+        if (egl.eglInitialize(display, null)) {
+            try {
+                String eglExtensions = egl.eglQueryString(display, EGL10.EGL_EXTENSIONS);
+                for (int i = 0; i < requiredEglList.length; ++i) {
+                    assertTrue("EGL Extension required by CDD section 7.1.4 missing: " +
+                               requiredEglList[i], hasExtension(eglExtensions, requiredEglList[i]));
+                }
+                if (hasExtension(eglExtensions, "EGL_KHR_mutable_render_buffer")) {
+                    assertTrue("Devices exposes EGL_KHR_mutable_render_buffer but not EGL_ANDROID_front_buffer_auto_refresh", hasExtension(eglExtensions, "EGL_ANDROID_front_buffer_auto_refresh"));
+                }
+            } finally {
+                egl.eglTerminate(display);
+            }
+        } else {
+            Log.e(TAG, "Couldn't initialize EGL.");
+        }
+    }
+
     private static boolean hasExtension(String extensions, String name) {
         return OpenGlEsVersionCtsActivity.hasExtension(extensions, name);
     }
diff --git a/tests/tests/opengl/src/android/opengl/cts/WrapperTest.java b/tests/tests/opengl/src/android/opengl/cts/WrapperTest.java
index 1faef87..c81520d 100644
--- a/tests/tests/opengl/src/android/opengl/cts/WrapperTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/WrapperTest.java
@@ -190,9 +190,12 @@
         // zero out the refcount.
         //
         // Before we can terminate we need to be sure that the display has been initialized
-        // at least once. Also includes the 1s sleep to work-around a suspected race condition
-        // where it seems that some earlier tests may not have completed clean-up of all activities.
-        Thread.sleep(1000);
+        // at least once so call eglSetup first.
+        //
+        // IMPORTANT NOTE: If a previous test in this test group fails to cleanup its
+        // GLSurfaceView there may be a crash here on some platforms due to an object destruction
+        // race condition. The solution is to make sure all previous tests override onPause()
+        // and call their GLSurfaceView's onPause() function there. See b/37118199 for history.
         eglSetup(2, 1, 1);
         for (int i = 0; i < 100; i++) {
             EGL14.eglTerminate(mEGLDisplay);
diff --git a/tests/tests/openglperf/Android.mk b/tests/tests/openglperf/Android.mk
index fcc2ba6..7669204 100644
--- a/tests/tests/openglperf/Android.mk
+++ b/tests/tests/openglperf/Android.mk
@@ -37,7 +37,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/openglperf/jni/Android.mk b/tests/tests/openglperf/jni/Android.mk
index d6df59b..3fe448a 100644
--- a/tests/tests/openglperf/jni/Android.mk
+++ b/tests/tests/openglperf/jni/Android.mk
@@ -28,4 +28,6 @@
 
 LOCAL_SDK_VERSION := 14
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index ccc72a1..1aa46cc 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -39,12 +39,13 @@
     src/android/os/cts/IParcelFileDescriptorPeer.aidl \
     src/android/os/cts/IEmptyService.aidl \
     src/android/os/cts/ISeccompIsolatedService.aidl \
-    src/android/os/cts/ISecondary.aidl
+    src/android/os/cts/ISecondary.aidl \
+    src/android/os/cts/ISharedMemoryService.aidl
 
 LOCAL_PACKAGE_NAME := CtsOsTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # uncomment when b/13282254 is fixed
 #LOCAL_SDK_VERSION := current
@@ -66,7 +67,7 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 cts_platform_version_path := cts/tests/tests/os/assets/platform_versions.txt
 cts_platform_version_string := $(shell cat $(cts_platform_version_path))
diff --git a/tests/tests/os/AndroidManifest.xml b/tests/tests/os/AndroidManifest.xml
index 846251f..a227cc3 100644
--- a/tests/tests/os/AndroidManifest.xml
+++ b/tests/tests/os/AndroidManifest.xml
@@ -76,6 +76,10 @@
             android:name="android.os.cts.CrossProcessExceptionService"
             android:process=":green"
             android:exported="true" />
+        <service
+            android:name="android.os.cts.SharedMemoryService"
+            android:process=":sharedmem"
+            android:exported="false" />
 
         <service android:name="android.os.cts.LocalService">
             <intent-filter>
diff --git a/tests/tests/os/jni/Android.mk b/tests/tests/os/jni/Android.mk
index ebc03e1..3d79d31 100644
--- a/tests/tests/os/jni/Android.mk
+++ b/tests/tests/os/jni/Android.mk
@@ -55,6 +55,7 @@
 	LOCAL_CFLAGS += -DARCH_SUPPORTS_SECCOMP
 endif
 
+LOCAL_CFLAGS := -Wno-unused-parameter
 LOCAL_CPPFLAGS_arm := -mcpu=generic
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/os/src/android/os/cts/EnvironmentTest.java b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
index 84ff5f4..6f259c3 100644
--- a/tests/tests/os/src/android/os/cts/EnvironmentTest.java
+++ b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
@@ -79,15 +79,16 @@
         // wider range, but we want to make sure the device isn't going totally
         // crazy; too few inodes can result in system instability, and too many
         // inodes can result in wasted space.
-        final long size = stat.f_blocks * stat.f_frsize;
-        final long minInodes = size / 32768;
-        final long maxInodes = size / 8192;
+        final long maxsize = stat.f_blocks * stat.f_frsize;
+        final long maxInodes = maxsize / 4096;
+        final long minsize = stat.f_bavail * stat.f_frsize;
+        final long minInodes = minsize / 32768;
 
-        if (stat.f_files >= minInodes && stat.f_files <= maxInodes) {
+        if (stat.f_ffree >= minInodes && stat.f_ffree <= maxInodes) {
             // Sweet, sounds great!
         } else {
-            fail("Number of inodes " + stat.f_files + " not within sane range for partition of "
-                    + size + " bytes; expected [" + minInodes + "," + maxInodes + "]");
+            fail("Number of inodes " + stat.f_ffree + " not within sane range for partition of "
+                    + minsize + "," + maxsize + " bytes; expected [" + minInodes + "," + maxInodes + "]");
         }
     }
 }
diff --git a/tests/tests/os/src/android/os/cts/ISharedMemoryService.aidl b/tests/tests/os/src/android/os/cts/ISharedMemoryService.aidl
new file mode 100644
index 0000000..651c62a
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/ISharedMemoryService.aidl
@@ -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.os.cts;
+
+import android.os.SharedMemory;
+
+interface ISharedMemoryService {
+    void setup(in SharedMemory memory, int prot);
+    byte read(int index);
+    void write(int index, byte value);
+}
diff --git a/tests/tests/os/src/android/os/cts/MemoryFileTest.java b/tests/tests/os/src/android/os/cts/MemoryFileTest.java
index def73b2..6e6eba8 100644
--- a/tests/tests/os/src/android/os/cts/MemoryFileTest.java
+++ b/tests/tests/os/src/android/os/cts/MemoryFileTest.java
@@ -56,7 +56,7 @@
             byte[] data = new byte[512];
             mMemoryFile.writeBytes(data, srcOffset, destOffset, count);
             fail("MemoryFile should throw IndexOutOfBoundsException here.");
-        } catch (IndexOutOfBoundsException e) {
+        } catch (IndexOutOfBoundsException | IllegalArgumentException e) {
             // expected
         }
     }
@@ -101,13 +101,10 @@
         mMemoryFile = new MemoryFile("Test File", 512);
         assertEquals(512, mMemoryFile.length());
 
-        mMemoryFile = new MemoryFile("Test File", 0);
-        assertEquals(0, mMemoryFile.length());
-
         try {
             mMemoryFile = new MemoryFile("Test File", -512);
             fail();
-        } catch (IOException expected) {
+        } catch (IOException | IllegalArgumentException expected) {
         }
     }
 
@@ -142,7 +139,7 @@
             byte[] data = new byte[512];
             mMemoryFile.readBytes(data, srcOffset, destOffset, count);
             fail("MemoryFile should throw IndexOutOfBoundsException here.");
-        } catch (IndexOutOfBoundsException e) {
+        } catch (IndexOutOfBoundsException | IllegalArgumentException e) {
             // expected
         }
     }
diff --git a/tests/tests/os/src/android/os/cts/PowerManager_WakeLockTest.java b/tests/tests/os/src/android/os/cts/PowerManager_WakeLockTest.java
index a643fc6..639493a 100644
--- a/tests/tests/os/src/android/os/cts/PowerManager_WakeLockTest.java
+++ b/tests/tests/os/src/android/os/cts/PowerManager_WakeLockTest.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
 import android.test.AndroidTestCase;
 
 public class PowerManager_WakeLockTest extends AndroidTestCase {
@@ -66,4 +67,14 @@
         Thread.sleep(PowerManagerTest.TIME + PowerManagerTest.MORE_TIME);
         assertFalse(wl.isHeld());
     }
+
+    public void testWakeLockTimeout() throws Exception {
+        final PowerManager pm = getContext().getSystemService(PowerManager.class);
+
+        final WakeLock lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        lock.acquire(2000);
+        SystemClock.sleep(4000);
+
+        lock.release();
+    }
 }
diff --git a/tests/tests/os/src/android/os/cts/SharedMemoryService.java b/tests/tests/os/src/android/os/cts/SharedMemoryService.java
new file mode 100644
index 0000000..fcc38d5
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/SharedMemoryService.java
@@ -0,0 +1,66 @@
+/*
+ * 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.os.cts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+
+import java.nio.ByteBuffer;
+
+public class SharedMemoryService extends Service {
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new SharedMemoryServiceImpl();
+    }
+
+    private static class SharedMemoryServiceImpl extends ISharedMemoryService.Stub {
+        private SharedMemory mSharedMemory;
+        private ByteBuffer mMappedBuffer;
+
+        @Override
+        public void setup(SharedMemory memory, int prot) throws RemoteException {
+            mSharedMemory = memory;
+            try {
+                mMappedBuffer = mSharedMemory.map(prot, 0, mSharedMemory.getSize());
+            } catch (ErrnoException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+
+        @Override
+        public byte read(int index) throws RemoteException {
+            // Although we expect only one client we need to insert memory barriers to ensure
+            // visibility
+            synchronized (mMappedBuffer) {
+                return mMappedBuffer.get(index);
+            }
+        }
+
+        @Override
+        public void write(int index, byte value) throws RemoteException {
+            // Although we expect only one client we need to insert memory barriers to ensure
+            // visibility
+            synchronized (mMappedBuffer) {
+                mMappedBuffer.put(index, value);
+            }
+        }
+    }
+}
diff --git a/tests/tests/os/src/android/os/cts/SharedMemoryTest.java b/tests/tests/os/src/android/os/cts/SharedMemoryTest.java
new file mode 100644
index 0000000..c40cdc8
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/SharedMemoryTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.os.cts;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static android.system.OsConstants.PROT_READ;
+import static android.system.OsConstants.PROT_WRITE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SharedMemory;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+
+import com.google.common.util.concurrent.AbstractFuture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SharedMemoryTest {
+
+    private Instrumentation mInstrumentation;
+    private Intent mRemoteIntent;
+    private PeerConnection mRemoteConnection;
+    private ISharedMemoryService mRemote;
+
+    public static class PeerConnection extends AbstractFuture<ISharedMemoryService>
+            implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            set(ISharedMemoryService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+
+        @Override
+        public ISharedMemoryService get() throws InterruptedException, ExecutionException {
+            try {
+                return get(5, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        final Context context = mInstrumentation.getContext();
+        // Bring up both remote processes and wire them to each other
+        mRemoteIntent = new Intent();
+        mRemoteIntent.setComponent(new ComponentName(
+                "android.os.cts", "android.os.cts.SharedMemoryService"));
+        mRemoteConnection = new PeerConnection();
+        getContext().bindService(mRemoteIntent, mRemoteConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+        mRemote = mRemoteConnection.get();
+    }
+
+    @After
+    public void tearDown() {
+        final Context context = mInstrumentation.getContext();
+        context.unbindService(mRemoteConnection);
+    }
+
+    @Test
+    public void testReadWrite() throws RemoteException, ErrnoException {
+        try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+            ByteBuffer buffer = sharedMemory.mapReadWrite();
+            mRemote.setup(sharedMemory, PROT_READ | PROT_WRITE);
+
+            byte expected = 5;
+            buffer.put(0, expected);
+            assertEquals(expected, buffer.get(0));
+            // Memory barrier
+            synchronized (sharedMemory) {}
+            assertEquals(expected, mRemote.read(0));
+            expected = 10;
+            mRemote.write(0, expected);
+            // Memory barrier
+            synchronized (sharedMemory) {}
+            assertEquals(expected, buffer.get(0));
+            SharedMemory.unmap(buffer);
+        }
+    }
+
+    @Test
+    public void testReadOnly() throws RemoteException, ErrnoException {
+        try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+            ByteBuffer buffer = sharedMemory.mapReadWrite();
+            sharedMemory.setProtect(PROT_READ);
+            mRemote.setup(sharedMemory, PROT_READ);
+
+            byte expected = 15;
+            buffer.put(0, expected);
+            assertEquals(expected, buffer.get(0));
+            // Memory barrier
+            synchronized (sharedMemory) {}
+            assertEquals(expected, mRemote.read(0));
+            expected = 20;
+            try {
+                mRemote.write(0, expected);
+                fail("write shouldn't have worked, should be read only");
+            } catch (Exception e) {}
+
+            buffer.put(0, expected);
+            assertEquals(expected, buffer.get(0));
+            // Memory barrier
+            synchronized (sharedMemory) {}
+            assertEquals(expected, mRemote.read(0));
+        }
+    }
+
+    @Test
+    public void testUseAfterClose() throws RemoteException, ErrnoException {
+        ByteBuffer buffer;
+        try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+            buffer = sharedMemory.mapReadWrite();
+            mRemote.setup(sharedMemory, PROT_READ | PROT_WRITE);
+        }
+        byte expected = 5;
+        buffer.put(0, expected);
+        assertEquals(expected, buffer.get(0));
+        // Memory barrier
+        synchronized (buffer) {}
+        assertEquals(expected, mRemote.read(0));
+        expected = 10;
+        mRemote.write(0, expected);
+        // Memory barrier
+        synchronized (buffer) {}
+        assertEquals(expected, buffer.get(0));
+        SharedMemory.unmap(buffer);
+    }
+
+    @Test
+    public void testGetFd() throws ErrnoException {
+        SharedMemory sharedMemory = SharedMemory.create("hello", 1024);
+        assertNotEquals(-1, sharedMemory.getFd());
+        assertNotNull(sharedMemory.getFileDescriptor());
+        assertTrue(sharedMemory.getFileDescriptor().valid());
+        sharedMemory.close();
+        assertEquals(-1, sharedMemory.getFd());
+        assertNotNull(sharedMemory.getFileDescriptor());
+        assertTrue(!sharedMemory.getFileDescriptor().valid());
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvalidCreate() throws ErrnoException {
+        SharedMemory.create(null, -1);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvalidMapProt() throws ErrnoException {
+        try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+            sharedMemory.map(-1, 0, 1);
+        }
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvalidSetProt() throws ErrnoException {
+        try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+            sharedMemory.setProtect(-1);
+        }
+    }
+
+    @Test
+    public void testSetProtAddProt() throws ErrnoException {
+        try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+            assertTrue(sharedMemory.setProtect(OsConstants.PROT_READ));
+            assertTrue(sharedMemory.setProtect(OsConstants.PROT_READ));
+            assertFalse(sharedMemory.setProtect(OsConstants.PROT_READ | OsConstants.PROT_WRITE));
+            assertTrue(sharedMemory.setProtect(OsConstants.PROT_NONE));
+            assertFalse(sharedMemory.setProtect(OsConstants.PROT_READ));
+        }
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testMapAfterClose() throws ErrnoException {
+        SharedMemory sharedMemory = SharedMemory.create(null, 1);
+        sharedMemory.close();
+        sharedMemory.mapReadWrite();
+    }
+
+    @Test(expected=ReadOnlyBufferException.class)
+    public void testWriteToReadOnly() throws ErrnoException {
+        try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+            sharedMemory.setProtect(PROT_READ);
+            ByteBuffer buffer = null;
+            try {
+                buffer = sharedMemory.mapReadWrite();
+                fail("Should have thrown an exception");
+            } catch (ErrnoException ex) {
+                assertEquals(OsConstants.EPERM, ex.errno);
+            }
+            buffer = sharedMemory.mapReadOnly();
+            assertTrue(buffer.isReadOnly());
+            buffer.put(0, (byte) 0);
+        }
+    }
+}
diff --git a/tests/tests/packageinstaller/adminpackageinstaller/Android.mk b/tests/tests/packageinstaller/adminpackageinstaller/Android.mk
index 95a607d..0e24292 100755
--- a/tests/tests/packageinstaller/adminpackageinstaller/Android.mk
+++ b/tests/tests/packageinstaller/adminpackageinstaller/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/packageinstaller/emptytestapp/Android.mk b/tests/tests/packageinstaller/emptytestapp/Android.mk
index b1171f1..d098318 100644
--- a/tests/tests/packageinstaller/emptytestapp/Android.mk
+++ b/tests/tests/packageinstaller/emptytestapp/Android.mk
@@ -25,6 +25,6 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/packageinstaller/externalsources/Android.mk b/tests/tests/packageinstaller/externalsources/Android.mk
index ca2fbda..d6477388 100755
--- a/tests/tests/packageinstaller/externalsources/Android.mk
+++ b/tests/tests/packageinstaller/externalsources/Android.mk
@@ -22,8 +22,6 @@
 
 LOCAL_PACKAGE_NAME := CtsExternalSourcesTestCases
 
-LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
-
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator android-support-test android-support-v4
@@ -31,7 +29,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/packageinstaller/externalsources/AndroidManifest.xml b/tests/tests/packageinstaller/externalsources/AndroidManifest.xml
index 33d1d6e..8bcdd04 100755
--- a/tests/tests/packageinstaller/externalsources/AndroidManifest.xml
+++ b/tests/tests/packageinstaller/externalsources/AndroidManifest.xml
@@ -21,13 +21,6 @@
 
     <application android:label="Cts External Sources Test">
         <uses-library android:name="android.test.runner"/>
-        <provider android:authorities="android.packageinstaller.externalsources.cts.fileprovider"
-                  android:name="android.support.v4.content.FileProvider"
-                  android:grantUriPermissions="true">
-            <meta-data
-                android:name="android.support.FILE_PROVIDER_PATHS"
-                android:resource="@xml/file_paths" />
-        </provider>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/packageinstaller/externalsources/AndroidTest.xml b/tests/tests/packageinstaller/externalsources/AndroidTest.xml
index 39d2d67..2d782d8 100644
--- a/tests/tests/packageinstaller/externalsources/AndroidTest.xml
+++ b/tests/tests/packageinstaller/externalsources/AndroidTest.xml
@@ -17,16 +17,6 @@
 <configuration description="Config for CTS External Sources test cases">
     <option name="config-descriptor:metadata" key="component" value="framework" />
 
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/cts/externalsources" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/cts"/>
-    </target_preparer>
-
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="cleanup" value="true" />
-        <option name="push" value="CtsEmptyTestApp.apk->/data/local/tmp/cts/externalsources/CtsEmptyTestApp.apk" />
-    </target_preparer>
-
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsExternalSourcesTestCases.apk" />
@@ -34,7 +24,7 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.packageinstaller.externalsources.cts" />
-        <option name="runtime-hint" value="1m" />
+        <option name="runtime-hint" value="10s" />
     </test>
 
 </configuration>
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 e10e278..921f5f1 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
@@ -15,122 +15,41 @@
  */
 package android.packageinstaller.externalsources.cts;
 
-import android.app.Instrumentation;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.support.v4.content.FileProvider;
-import android.util.Log;
 
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 
 @RunWith(AndroidJUnit4.class)
-@MediumTest
+@SmallTest
 public class ExternalSourcesTest {
 
-    private static final String TAG = ExternalSourcesTest.class.getSimpleName();
-    private static final String TEST_APK_NAME = "CtsEmptyTestApp.apk";
-    private static final String TEST_APK_EXTERNAL_LOCATION = "/data/local/tmp/cts/externalsources";
-    private static final String CONTENT_AUTHORITY =
-            "android.packageinstaller.externalsources.cts.fileprovider";
-    private static final String PACKAGE_INSTALLER_PACKAGE_NAME = "com.android.packageinstaller";
-    private static final String INSTALL_CONFIRM_TEXT_ID = "install_confirm_question";
-    private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
-    private static final String ALERT_DIALOG_TITLE_ID = "android:id/alertTitle";
-
-    private static final long WAIT_FOR_UI_TIMEOUT = 5000;
-
     private Context mContext;
     private PackageManager mPm;
-    private Instrumentation mInstrumentation;
     private String mPackageName;
-    private File mApkFile;
     private UiDevice mUiDevice;
-
-    @BeforeClass
-    public static void setUpOnce() throws IOException {
-        File srcApkFile = new File(TEST_APK_EXTERNAL_LOCATION, TEST_APK_NAME);
-        File destApkFile = new File(InstrumentationRegistry.getTargetContext().getFilesDir(),
-                TEST_APK_NAME);
-        copyFile(srcApkFile, destApkFile);
-    }
+    private boolean mHasFeature;
 
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mPm = mContext.getPackageManager();
         mPackageName = mContext.getPackageName();
-        mApkFile = new File(mContext.getFilesDir(), TEST_APK_NAME);
-        mUiDevice = UiDevice.getInstance(mInstrumentation);
-        if (!mUiDevice.isScreenOn()) {
-            mUiDevice.wakeUp();
-        }
-        mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
-    }
-
-    private static void copyFile(File srcFile, File destFile) throws IOException {
-        if (destFile.exists()) {
-            destFile.delete();
-        }
-        FileInputStream inputStream = new FileInputStream(srcFile);
-        FileOutputStream out = new FileOutputStream(destFile);
-        try {
-            byte[] buffer = new byte[4096];
-            int bytesRead;
-            while ((bytesRead = inputStream.read(buffer)) >= 0) {
-                out.write(buffer, 0, bytesRead);
-            }
-            Log.d(TAG, "copied file " + srcFile + " to " + destFile);
-        } finally {
-            out.flush();
-            try {
-                out.getFD().sync();
-            } catch (IOException e) {
-            }
-            out.close();
-            inputStream.close();
-        }
-    }
-
-    private void launchPackageInstaller() {
-        Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
-        intent.setData(FileProvider.getUriForFile(mContext, CONTENT_AUTHORITY, mApkFile));
-        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        Log.d(TAG, "Starting intent with uri " + intent.getDataString());
-        mContext.startActivity(intent);
-    }
-
-    private void assertInstallAllowed(String errorMessage) {
-        BySelector selector = By.res(PACKAGE_INSTALLER_PACKAGE_NAME, INSTALL_CONFIRM_TEXT_ID);
-        UiObject2 uiObject = mUiDevice.wait(Until.findObject(selector), WAIT_FOR_UI_TIMEOUT);
-        Assert.assertNotNull(errorMessage, uiObject);
-        mUiDevice.pressBack();
-    }
-
-    private void assertInstallBlocked(String errorMessage) {
-        BySelector selector = By.res(ALERT_DIALOG_TITLE_ID);
-        UiObject2 settingsButton = mUiDevice.wait(Until.findObject(selector), WAIT_FOR_UI_TIMEOUT);
-        Assert.assertNotNull(errorMessage, settingsButton);
-        mUiDevice.pressBack();
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mHasFeature = !mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
     }
 
     private void setAppOpsMode(String mode) throws IOException {
@@ -144,35 +63,39 @@
     @Test
     public void blockedSourceTest() throws Exception {
         setAppOpsMode("deny");
-        boolean isTrusted = mPm.canRequestPackageInstalls();
+        final boolean isTrusted = mPm.canRequestPackageInstalls();
         Assert.assertFalse("Package " + mPackageName
                 + " allowed to install packages after setting app op to errored", isTrusted);
-        launchPackageInstaller();
-        assertInstallBlocked("Install blocking dialog not shown when app op set to errored");
     }
 
     @Test
     public void allowedSourceTest() throws Exception {
         setAppOpsMode("allow");
-        boolean isTrusted = mPm.canRequestPackageInstalls();
+        final boolean isTrusted = mPm.canRequestPackageInstalls();
         Assert.assertTrue("Package " + mPackageName
                 + " blocked from installing packages after setting app op to allowed", isTrusted);
-        launchPackageInstaller();
-        assertInstallAllowed("Install confirmation not shown when app op set to allowed");
     }
 
     @Test
     public void defaultSourceTest() throws Exception {
-        boolean isTrusted = mPm.canRequestPackageInstalls();
+        setAppOpsMode("default");
+        final boolean isTrusted = mPm.canRequestPackageInstalls();
         Assert.assertFalse("Package " + mPackageName
                 + " with default app ops state allowed to install packages", isTrusted);
-        launchPackageInstaller();
-        assertInstallBlocked("Install blocking dialog not shown when app op set to default");
+    }
+
+    @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);
     }
 
     @After
     public void tearDown() throws Exception {
-        mUiDevice.pressHome();
         setAppOpsMode("default");
     }
 }
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index a88bb01..b24774f 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
diff --git a/tests/tests/permission/jni/Android.mk b/tests/tests/permission/jni/Android.mk
index 91c0540..2e64d47 100644
--- a/tests/tests/permission/jni/Android.mk
+++ b/tests/tests/permission/jni/Android.mk
@@ -31,4 +31,6 @@
 LOCAL_SDK_VERSION := 23
 LOCAL_CPPFLAGS := -std=gnu++11
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/permission/res/drawable/robot.png b/tests/tests/permission/res/drawable/robot.png
new file mode 100644
index 0000000..8a9e698
--- /dev/null
+++ b/tests/tests/permission/res/drawable/robot.png
Binary files differ
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 0318610..79ee799 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -19,6 +19,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Environment;
+import android.system.ErrnoException;
+import android.util.Pair;
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructStatVfs;
@@ -28,6 +30,7 @@
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileFilter;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -36,6 +39,9 @@
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executors;
@@ -43,9 +49,12 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
@@ -160,6 +169,24 @@
         assertFalse(f.canExecute());
     }
 
+    /* b/26813932 */
+    @MediumTest
+    public void testProcInterruptsNotReadable() throws Exception {
+        File f = new File("/proc/interrupts");
+        assertFalse(f.canRead());
+        assertFalse(f.canWrite());
+        assertFalse(f.canExecute());
+    }
+
+    /* b/26813932 */
+    @MediumTest
+    public void testProcStatNotReadable() throws Exception {
+        File f = new File("/proc/stat");
+        assertFalse(f.canRead());
+        assertFalse(f.canWrite());
+        assertFalse(f.canExecute());
+    }
+
     @MediumTest
     public void testDevMemSane() throws Exception {
         File f = new File("/dev/mem");
@@ -258,17 +285,78 @@
         assertFalse(f.canExecute());
     }
 
-    @MediumTest
-    public void testProcSelfPagemapNotAccessible() {
-        // Note: can't use f.canRead() here, since the security check is done
-        // during the open() process. access(R_OK) return OK even through
-        // open() eventually fails.
+    private static List<Pair<Long, Long>> mappedPageRanges() throws IOException {
+        final BigInteger PAGE_SIZE = new BigInteger("4096");
+
+        final Pattern mapsPattern = Pattern.compile("^(\\p{XDigit}+)-(\\p{XDigit}+)");
+        List<Pair<Long, Long>> ret = new LinkedList<>();
+
+        BufferedReader reader = new BufferedReader(new FileReader("/proc/self/maps"));
+        String line;
         try {
-            new FileInputStream("/proc/self/pagemap");
-            fail("Device is missing the following kernel security patch: "
-                 + "https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ab676b7d6fbf4b294bf198fb27ade5b0e865c7ce");
-        } catch (FileNotFoundException e) {
-            // expected
+            while ((line = reader.readLine()) != null) {
+                Matcher m = mapsPattern.matcher(line);
+                m.find();
+
+                long start = new BigInteger(m.group(1), 16).divide(PAGE_SIZE).longValue();
+                long end = new BigInteger(m.group(2), 16).divide(PAGE_SIZE).longValue();
+
+                ret.add(new Pair<>(start, end));
+            }
+
+            return ret;
+        } finally {
+            reader.close();
+        }
+    }
+
+    private static boolean pfnIsZero(FileDescriptor pagemap, long start, long end) throws ErrnoException, IOException {
+        // Note: reads from /proc/self/pagemap *must* be 64-bit aligned.  Use low-level android.system.Os routines to
+        // ensure this.
+        final int SIZEOF_U64 = 8;
+        final long PAGE_PRESENT = 1L << 63;
+        final long PFN_MASK = (1L << 55) - 1;
+
+        for (long page = start; page < end; page++) {
+            long offset = page * SIZEOF_U64;
+            long seek = Os.lseek(pagemap, offset, OsConstants.SEEK_SET);
+            if (offset != seek)
+                throw new IOException("lseek(" + offset + ") returned " + seek);
+
+            byte bytes[] = new byte[SIZEOF_U64];
+            ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.nativeOrder());
+            int read = Os.read(pagemap, buf);
+            if (read != bytes.length)
+                throw new IOException("read(" + bytes.length + ") returned " + read);
+
+            buf.position(0);
+            long entry = buf.getLong();
+            if ((entry & PAGE_PRESENT) == PAGE_PRESENT && (entry & PFN_MASK) != 0)
+                return false;
+        }
+
+        return true;
+    }
+
+    @MediumTest
+    public void testProcSelfPagemapSane() throws ErrnoException, IOException {
+        FileDescriptor pagemap = null;
+        try {
+            pagemap = Os.open("/proc/self/pagemap", OsConstants.O_RDONLY, 0);
+
+            for (Pair<Long, Long> range : mappedPageRanges())
+                if (!pfnIsZero(pagemap, range.first, range.second))
+                    fail("Device is missing the following kernel security patch: "
+                         + "https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ab676b7d6fbf4b294bf198fb27ade5b0e865c7ce");
+        } catch (ErrnoException e) {
+            if (e.errno == OsConstants.EPERM)
+                // expected before 4.2
+                return;
+
+            throw e;
+        } finally {
+            if (pagemap != null)
+                Os.close(pagemap);
         }
     }
 
diff --git a/tests/tests/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java b/tests/tests/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java
new file mode 100644
index 0000000..ad32923
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.permission.cts;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.media.MediaPlayer;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.WifiLock;
+import android.os.PowerManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static android.app.WallpaperManager.FLAG_LOCK;
+
+/**
+ * Verify that Wallpaper-related operations enforce the correct permissions.
+ */
+public class NoWallpaperPermissionsTest extends AndroidTestCase {
+    private WallpaperManager mWM;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mWM = (WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE);
+    }
+
+    /**
+     * Verify that the setResource(...) methods enforce the SET_WALLPAPER permission
+     */
+    @SmallTest
+    public void testSetResource() throws IOException {
+        if (wallpaperNotSupported()) {
+            return;
+        }
+
+        try {
+            mWM.setResource(R.drawable.robot);
+            fail("WallpaperManager.setResource(id) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            mWM.setResource(R.drawable.robot, FLAG_LOCK);
+            fail("WallpaperManager.setResource(id, which) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+    }
+
+    /**
+     * Verify that the setBitmap(...) methods enforce the SET_WALLPAPER permission
+     */
+    @SmallTest
+    public void testSetBitmap() throws IOException  {
+        if (wallpaperNotSupported()) {
+            return;
+        }
+
+        Bitmap b = Bitmap.createBitmap(160, 120, Bitmap.Config.RGB_565);
+
+        try {
+            mWM.setBitmap(b);
+            fail("setBitmap(b) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            mWM.setBitmap(b, null, false);
+            fail("setBitmap(b, crop, allowBackup) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            mWM.setBitmap(b, null, false, FLAG_SYSTEM);
+            fail("setBitmap(b, crop, allowBackup, which) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+    }
+
+    /**
+     * Verify that the setStream(...) methods enforce the SET_WALLPAPER permission
+     */
+    @SmallTest
+    public void testSetStream() throws IOException  {
+        if (wallpaperNotSupported()) {
+            return;
+        }
+
+        ByteArrayInputStream stream = new ByteArrayInputStream(new byte[32]);
+
+        try {
+            mWM.setStream(stream);
+            fail("setStream(stream) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            mWM.setStream(stream, null, false);
+            fail("setStream(stream, crop, allowBackup) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            mWM.setStream(stream, null, false, FLAG_LOCK);
+            fail("setStream(stream, crop, allowBackup, which) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+    }
+
+    /**
+     * Verify that the clearWallpaper(...) methods enforce the SET_WALLPAPER permission
+     */
+    @SmallTest
+    public void testClearWallpaper() throws IOException  {
+        if (wallpaperNotSupported()) {
+            return;
+        }
+
+        try {
+            mWM.clear();
+            fail("clear() did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            mWM.clear(FLAG_SYSTEM);
+            fail("clear(which) did not enforce SET_WALLPAPER");
+        } catch (SecurityException expected) { /* expected */ }
+    }
+
+    /**
+     * Verify that reading the current wallpaper requires READ_EXTERNAL_STORAGE
+     */
+    @SmallTest
+    public void testReadWallpaper() {
+        if (wallpaperNotSupported()) {
+            return;
+        }
+
+        try {
+            /* ignore result */ mWM.getFastDrawable();
+            fail("getFastDrawable() did not enforce READ_EXTERNAL_STORAGE");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            /* ignore result */ mWM.peekFastDrawable();
+            fail("peekFastDrawable() did not enforce READ_EXTERNAL_STORAGE");
+        } catch (SecurityException expected) { /* expected */ }
+
+        try {
+            /* ignore result */ mWM.getWallpaperFile(FLAG_SYSTEM);
+            fail("getWallpaperFile(FLAG_SYSTEM) did not enforce READ_EXTERNAL_STORAGE");
+        } catch (SecurityException expected) { /* expected */ }
+    }
+
+    // ---------- Utility methods ----------
+
+    private boolean wallpaperNotSupported() {
+        return !(mWM.isWallpaperSupported() && mWM.isSetWallpaperAllowed());
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/ServicePermissionTest.java b/tests/tests/permission/src/android/permission/cts/ServicePermissionTest.java
new file mode 100644
index 0000000..6c10f1d
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/ServicePermissionTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.permission.cts;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The security designs of many system features require that a special
+ * permission is only ever granted to the core system (typically
+ * {@code system_server}), since it's the only process that should be binding
+ * into sensitive app code.
+ * <p>
+ * No apps outside the {@code system_server} should <em>ever</em> attempt to
+ * acquire these permissions.
+ */
+public class ServicePermissionTest extends AndroidTestCase {
+    public static String[] sServicePermissions = {
+            android.Manifest.permission.ACCOUNT_MANAGER,
+            android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
+            android.Manifest.permission.BIND_AUTOFILL_SERVICE,
+            android.Manifest.permission.BIND_CHOOSER_TARGET_SERVICE,
+            android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE,
+            // android.Manifest.permission.BIND_DEVICE_ADMIN,
+            android.Manifest.permission.BIND_DREAM_SERVICE,
+            android.Manifest.permission.BIND_INPUT_METHOD,
+            android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE,
+            // android.Manifest.permission.BIND_NFC_SERVICE,
+            android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE,
+            android.Manifest.permission.BIND_PRINT_SERVICE,
+            // android.Manifest.permission.BIND_QUICK_SETTINGS_TILE,
+            android.Manifest.permission.BIND_TEXT_SERVICE,
+            android.Manifest.permission.BIND_VOICE_INTERACTION,
+            android.Manifest.permission.BIND_VPN_SERVICE,
+            android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
+    };
+
+    public void testServicePermissions() {
+        final PackageManager pm = getContext().getPackageManager();
+
+        final List<String> failures = new ArrayList<>();
+        for (String perm : sServicePermissions) {
+            final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(
+                    new String[] { perm }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+            for (PackageInfo pi : holding) {
+                if (!Objects.equals("android", pi.packageName)) {
+                    failures.add(perm + " held by " + pi.packageName);
+                }
+            }
+        }
+        if (!failures.isEmpty()) {
+            fail("Found permissions granted to packages outside of the core system: "
+                    + failures.toString());
+        }
+    }
+}
diff --git a/tests/tests/permission2/Android.mk b/tests/tests/permission2/Android.mk
index be984c5..062aeb7 100755
--- a/tests/tests/permission2/Android.mk
+++ b/tests/tests/permission2/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_LIBRARIES := telephony-common
 
diff --git a/tests/tests/preference/Android.mk b/tests/tests/preference/Android.mk
index c56ced8..9223ce8 100644
--- a/tests/tests/preference/Android.mk
+++ b/tests/tests/preference/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test
 
diff --git a/tests/tests/preference2/Android.mk b/tests/tests/preference2/Android.mk
index b5fb0a2..7529f43 100644
--- a/tests/tests/preference2/Android.mk
+++ b/tests/tests/preference2/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
diff --git a/tests/tests/print/Android.mk b/tests/tests/print/Android.mk
index 527fe48..c9b036a 100644
--- a/tests/tests/print/Android.mk
+++ b/tests/tests/print/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 87e6c6e..ebcd41e 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -16,6 +16,8 @@
 
 package android.print.cts;
 
+import static android.content.pm.PackageManager.GET_META_DATA;
+import static android.content.pm.PackageManager.GET_SERVICES;
 import static android.print.cts.Utils.getPrintManager;
 
 import static org.junit.Assert.assertFalse;
@@ -35,6 +37,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.pdf.PdfDocument;
 import android.os.Bundle;
@@ -47,7 +50,6 @@
 import android.print.PrintDocumentAdapter.LayoutResultCallback;
 import android.print.PrintDocumentAdapter.WriteResultCallback;
 import android.print.PrintDocumentInfo;
-import android.print.PrintManager;
 import android.print.PrinterId;
 import android.print.cts.services.PrintServiceCallbacks;
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
@@ -56,7 +58,6 @@
 import android.print.pdf.PrintedPdfDocument;
 import android.printservice.CustomPrinterIconCallback;
 import android.printservice.PrintJob;
-import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
@@ -121,6 +122,8 @@
     private int mTestId;
     private PrintDocumentActivity mActivity;
 
+    private static String sDisabledPrintServicesBefore;
+
     private static final SparseArray<BasePrintTest> sIdToTest = new SparseArray<>();
 
     public final @Rule ShouldStartActivity mShouldStartActivityRule = new ShouldStartActivity();
@@ -198,6 +201,8 @@
         clearPrintSpoolerData();
         Log.d(LOG_TAG, "disableImes()");
         disableImes();
+        Log.d(LOG_TAG, "disablePrintServices()");
+        disablePrintServices(instrumentation.getTargetContext().getPackageName());
 
         // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
         // Dexmaker is used by mockito.
@@ -207,34 +212,54 @@
         Log.d(LOG_TAG, "setUpClass() done");
     }
 
-    @Before
-    public void setUp() throws Exception {
-        Log.d(LOG_TAG, "setUp()");
-
+    /**
+     * Disable all print services beside the ones we want to leave enabled.
+     *
+     * @param packageToLeaveEnabled The package of the services to leave enabled.
+     */
+    private static void disablePrintServices(@NonNull String packageToLeaveEnabled)
+            throws IOException {
         Instrumentation instrumentation = getInstrumentation();
 
-        assumeTrue(instrumentation.getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_PRINTING));
+        sDisabledPrintServicesBefore = SystemUtil.runShellCommand(instrumentation,
+                "settings get secure " + Settings.Secure.DISABLED_PRINT_SERVICES);
 
-        final PrintManager printManager = instrumentation.getContext()
-                .getSystemService(PrintManager.class);
-        final List<PrintServiceInfo> services = printManager.getPrintServices(
-                PrintManager.ALL_SERVICES);
-        final String targetPackageName = instrumentation.getTargetContext().getPackageName();
+        Intent printServiceIntent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+        List<ResolveInfo> installedServices = instrumentation.getContext().getPackageManager()
+                .queryIntentServices(printServiceIntent, GET_SERVICES | GET_META_DATA);
+
         StringBuilder builder = new StringBuilder();
-        for (PrintServiceInfo service : services) {
-            final ComponentName serviceComponent = service.getComponentName();
-            if (targetPackageName.equals(serviceComponent.getPackageName())) {
+        for (ResolveInfo service : installedServices) {
+            if (packageToLeaveEnabled.equals(service.serviceInfo.packageName)) {
                 continue;
             }
             if (builder.length() > 0) {
                 builder.append(":");
             }
-            builder.append(serviceComponent.flattenToString());
-            SystemUtil.runShellCommand(instrumentation, "settings put secure "
-                    + Settings.Secure.DISABLED_PRINT_SERVICES + " " + builder);
+            builder.append(new ComponentName(service.serviceInfo.packageName,
+                    service.serviceInfo.name).flattenToString());
         }
 
+        SystemUtil.runShellCommand(instrumentation, "settings put secure "
+                + Settings.Secure.DISABLED_PRINT_SERVICES + " " + builder);
+    }
+
+    /**
+     * Revert {@link #disablePrintServices(String)}
+     */
+    private static  void enablePrintServices() throws IOException {
+        SystemUtil.runShellCommand(getInstrumentation(),
+                "settings put secure " + Settings.Secure.DISABLED_PRINT_SERVICES + " "
+                        + sDisabledPrintServicesBefore);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        Log.d(LOG_TAG, "setUp()");
+
+        assumeTrue(getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_PRINTING));
+
         // Initialize the latches.
         Log.d(LOG_TAG, "init counters");
         mCancelOperationCounter = new CallCounter();
@@ -275,6 +300,9 @@
 
         Instrumentation instrumentation = getInstrumentation();
 
+        Log.d(LOG_TAG, "enablePrintServices()");
+        enablePrintServices();
+
         Log.d(LOG_TAG, "enableImes()");
         enableImes();
 
diff --git a/tests/tests/proto/Android.mk b/tests/tests/proto/Android.mk
index 58126e2..f4fcea2 100644
--- a/tests/tests/proto/Android.mk
+++ b/tests/tests/proto/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_PACKAGE_NAME := CtsProtoTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 #LOCAL_SDK_VERSION := current
 LOCAL_JAVA_LIBRARIES += android.test.runner
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index 3b71035..d4b3e99 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -26,17 +26,16 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_JAVA_LIBRARIES := android.test.mock legacy-android-test telephony-common
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-v4 \
     compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
-    junit \
-    legacy-android-test
+    junit
 
 LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java b/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
index fad1019..b11fad2 100644
--- a/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
@@ -51,6 +51,8 @@
     private static final String mmsBody = "MMS body CTS";
 
     private static final String[] ID_PROJECTION = new String[] { BaseColumns._ID };
+    private static final String[] ID_TEXT_ONLY_PROJECTION = new String[] { BaseColumns._ID,
+            Telephony.Mms.TEXT_ONLY };
     private static final String SMS_SELECTION = Telephony.Sms.ADDRESS + " = ? and "
             + Telephony.Sms.BODY + " = ?";
 
@@ -130,7 +132,7 @@
     /**
      * Test adds 2 SMS messages, 1 text-only MMS messages and 1 non-text-only, runs backup,
      * deletes the messages from the provider, runs restore, check if the messages are in the
-     * provider (w/o non-text-only one).
+     * provider (with non-text-only one).
      * @throws Exception
      */
     public void testSmsBackupRestore() throws Exception {
@@ -163,39 +165,42 @@
         assertEquals(1,
                 mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody2));
 
-        try (Cursor mmsCursor = mContentResolver.query(Telephony.Mms.CONTENT_URI, ID_PROJECTION,
-                MMS_SELECTION, new String[] {mmsSubject}, null)) {
+        try (Cursor mmsCursor = mContentResolver.query(Telephony.Mms.CONTENT_URI,
+              ID_TEXT_ONLY_PROJECTION, MMS_SELECTION, new String[] {mmsSubject}, null)) {
             assertNotNull(mmsCursor);
-            assertEquals(1, mmsCursor.getCount());
-            mmsCursor.moveToFirst();
-            final long mmsId = mmsCursor.getLong(0);
-            final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon()
-                    .appendPath(String.valueOf(mmsId)).appendPath("part").build();
-            // Check the body.
-            try (Cursor partCursor = mContentResolver.query(partUri, MMS_PART_TEXT_PROJECTION,
+            assertEquals(2, mmsCursor.getCount());
+            for (mmsCursor.moveToFirst(); !mmsCursor.isAfterLast(); mmsCursor.moveToNext()) {
+              final long mmsId = mmsCursor.getLong(0);
+              final long mmsTextOnly = mmsCursor.getLong(1);
+              assertEquals(mmsTextOnly, 1);
+              final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon()
+                  .appendPath(String.valueOf(mmsId)).appendPath("part").build();
+              // Check the body.
+              try (Cursor partCursor = mContentResolver.query(partUri, MMS_PART_TEXT_PROJECTION,
                     MMS_PART_TEXT_SELECTION, new String[]{ ContentType.TEXT_PLAIN }, null)) {
                 assertNotNull(partCursor);
                 assertEquals(1, partCursor.getCount());
                 assertTrue(partCursor.moveToFirst());
-                assertEquals(mmsBody, partCursor.getString(0));
-            }
+                assertTrue(partCursor.getString(0).startsWith(mmsBody));
+              }
 
-            // Check if there are 2 parts (smil and body).
-            assertEquals(2, mContentResolver.delete(partUri, MMS_PART_SELECTION,
+              // Check if there are 2 parts (smil and body).
+              assertEquals(2, mContentResolver.delete(partUri, MMS_PART_SELECTION,
                     new String[]{String.valueOf(mmsId)}));
 
-            // Check addresses.
-            final Uri addrUri = getMmsAddrUri(mmsId);
-            try (Cursor addrCursor = mContentResolver.query(addrUri, MMS_ADDR_PROJECTION,
+              // Check addresses.
+              final Uri addrUri = getMmsAddrUri(mmsId);
+              try (Cursor addrCursor = mContentResolver.query(addrUri, MMS_ADDR_PROJECTION,
                     MMS_ADDR_SELECTION, new String[]{String.valueOf(mmsId)}, null)) {
                 assertNotNull(addrCursor);
                 for (String addr : mmsAddresses) {
-                    addrCursor.moveToNext();
-                    assertEquals(addr, addrCursor.getString(0));
+                  addrCursor.moveToNext();
+                  assertEquals(addr, addrCursor.getString(0));
                 }
-            }
-            assertEquals(mmsAddresses.length, mContentResolver.delete(addrUri, MMS_ADDR_SELECTION,
+              }
+              assertEquals(mmsAddresses.length, mContentResolver.delete(addrUri, MMS_ADDR_SELECTION,
                     new String[]{String.valueOf(mmsId)}));
+            }
         }
     }
 
@@ -257,4 +262,4 @@
         ProviderTestUtils.wipeBackup(LOCAL_BACKUP_COMPONENT, TELEPHONY_PROVIDER_PACKAGE,
                 mUiAutomation);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/renderscript/Android.mk b/tests/tests/renderscript/Android.mk
index a4ccf42..1a8c549 100644
--- a/tests/tests/renderscript/Android.mk
+++ b/tests/tests/renderscript/Android.mk
@@ -41,7 +41,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/renderscriptlegacy/Android.mk b/tests/tests/renderscriptlegacy/Android.mk
index fb93d05..8114642 100644
--- a/tests/tests/renderscriptlegacy/Android.mk
+++ b/tests/tests/renderscriptlegacy/Android.mk
@@ -31,6 +31,6 @@
 LOCAL_SDK_VERSION := 19
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/rsblas/Android.mk b/tests/tests/rsblas/Android.mk
index d67ba09..0385573 100644
--- a/tests/tests/rsblas/Android.mk
+++ b/tests/tests/rsblas/Android.mk
@@ -35,7 +35,7 @@
 LOCAL_RENDERSCRIPT_FLAGS := -Wno-error=deprecated-declarations
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/rscpp/Android.mk b/tests/tests/rscpp/Android.mk
index e5a7fdc..11957bf 100644
--- a/tests/tests/rscpp/Android.mk
+++ b/tests/tests/rscpp/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 include $(LOCAL_PATH)/librscpptest/Android.mk
diff --git a/tests/tests/rscpp/librscpptest/Android.mk b/tests/tests/rscpp/librscpptest/Android.mk
index 36eafe2..5621c02 100644
--- a/tests/tests/rscpp/librscpptest/Android.mk
+++ b/tests/tests/rscpp/librscpptest/Android.mk
@@ -46,6 +46,7 @@
 LOCAL_C_INCLUDES += frameworks/rs
 
 LOCAL_CPPFLAGS := -std=c++11
+LOCAL_CFLAGS := -Wno-unused-parameter
 
 LOCAL_SHARED_LIBRARIES := libdl liblog
 LOCAL_STATIC_LIBRARIES := libRScpp_static
diff --git a/tests/tests/sax/Android.mk b/tests/tests/sax/Android.mk
index cf354df..0c2a2b3 100644
--- a/tests/tests/sax/Android.mk
+++ b/tests/tests/sax/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 4fb95ee..b22f6c7 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -51,7 +51,7 @@
 #LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 118744e..dd069fe 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -46,4 +46,6 @@
 LOCAL_C_INCLUDES += ndk/sources/cpufeatures
 LOCAL_STATIC_LIBRARIES := cpufeatures
 
+LOCAL_CFLAGS := -Wno-unused-parameter
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/security/res/raw/bug_37662286.gif b/tests/tests/security/res/raw/bug_37662286.gif
new file mode 100644
index 0000000..f8ecc27
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_37662286.gif
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/Movie33897722.java b/tests/tests/security/src/android/security/cts/Movie33897722.java
index e14ded1..3e36fa8 100644
--- a/tests/tests/security/src/android/security/cts/Movie33897722.java
+++ b/tests/tests/security/src/android/security/cts/Movie33897722.java
@@ -40,16 +40,34 @@
      * color map, which would be reading memory that we do not control, and may be uninitialized.
      */
     public void test_android_bug_33897722() {
-        InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_33897722);
-        Movie movie = Movie.decodeStream(exploitImage);
-        assertNotNull(movie);
-        assertEquals(movie.width(), 600);
-        assertEquals(movie.height(), 752);
-
         // The image has a 10 x 10 frame on top of a transparent background. Only test the
         // 10 x 10 frame, since the original bug would never have used uninitialized memory
         // outside of it.
-        Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+        test_movie(R.raw.bug_33897722, 600, 752, 10, 10);
+    }
+
+    public void test_android_bug_37662286() {
+        // The image has a background color that is out of range. Arbitrarily test
+        // the upper left corner. (Most of the image is transparent.)
+        test_movie(R.raw.bug_37662286, 453, 272, 10, 10);
+    }
+
+    /**
+     * Test that a Movie draws transparent where it should.
+     *
+     * Old code read uninitialized memory. This ensures that we fall back to transparent.
+     */
+    private void test_movie(int resId, int screenWidth, int screenHeight,
+                            int drawWidth, int drawHeight) {
+        assertTrue(drawWidth <= screenWidth && drawHeight <= screenHeight);
+
+        InputStream exploitImage = mContext.getResources().openRawResource(resId);
+        Movie movie = Movie.decodeStream(exploitImage);
+        assertNotNull(movie);
+        assertEquals(movie.width(), screenWidth);
+        assertEquals(movie.height(), screenHeight);
+
+        Bitmap bitmap = Bitmap.createBitmap(drawWidth, drawHeight, Bitmap.Config.ARGB_8888);
         Canvas canvas = new Canvas(bitmap);
 
         // Use Src PorterDuff mode, to see exactly what the Movie creates.
@@ -58,8 +76,8 @@
 
         movie.draw(canvas, 0, 0, paint);
 
-        for (int x = 0; x < 10; x++) {
-            for (int y = 0; y < 10; y++) {
+        for (int x = 0; x < drawWidth; x++) {
+            for (int y = 0; y < drawHeight; y++) {
                 assertEquals(bitmap.getPixel(x, y), Color.TRANSPARENT);
             }
         }
diff --git a/tests/tests/security/testeffect/Android.mk b/tests/tests/security/testeffect/Android.mk
index a7e3cac..7e4ab93 100644
--- a/tests/tests/security/testeffect/Android.mk
+++ b/tests/tests/security/testeffect/Android.mk
@@ -28,5 +28,6 @@
 LOCAL_C_INCLUDES := \
   $(call include-path-for, audio-effects)
 
+LOCAL_CFLAGS := -Wno-unused-parameter
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/selinux/selinuxTargetSdk/Android.mk b/tests/tests/selinux/selinuxTargetSdk/Android.mk
index 138da59..a0923ee 100755
--- a/tests/tests/selinux/selinuxTargetSdk/Android.mk
+++ b/tests/tests/selinux/selinuxTargetSdk/Android.mk
@@ -17,11 +17,11 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := \
     compatibility-device-util \
-    ctstestrunner \
-    legacy-android-test
+    ctstestrunner
+LOCAL_JAVA_LIBRARIES := legacy-android-test
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_PACKAGE_NAME := CtsSelinuxTargetSdkTestCases
 LOCAL_SDK_VERSION := current
diff --git a/tests/tests/selinux/selinuxTargetSdk2/Android.mk b/tests/tests/selinux/selinuxTargetSdk2/Android.mk
index 49a0868..f475f9f 100755
--- a/tests/tests/selinux/selinuxTargetSdk2/Android.mk
+++ b/tests/tests/selinux/selinuxTargetSdk2/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := \
     compatibility-device-util \
     ctstestrunner \
diff --git a/tests/tests/shortcutmanager/Android.mk b/tests/tests/shortcutmanager/Android.mk
index ec5d89a..29333aa 100755
--- a/tests/tests/shortcutmanager/Android.mk
+++ b/tests/tests/shortcutmanager/Android.mk
@@ -36,7 +36,7 @@
 
 LOCAL_PACKAGE_NAME := CtsShortcutManagerTestCases
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/tests/shortcutmanager/packages/launchermanifest/Android.mk b/tests/tests/shortcutmanager/packages/launchermanifest/Android.mk
index 8c0bdb7..5774466 100644
--- a/tests/tests/shortcutmanager/packages/launchermanifest/Android.mk
+++ b/tests/tests/shortcutmanager/packages/launchermanifest/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.launcher1
 
@@ -68,7 +68,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.launcher2
 
@@ -98,7 +98,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.launcher3
 
diff --git a/tests/tests/shortcutmanager/packages/launchermanifest_nonshared/Android.mk b/tests/tests/shortcutmanager/packages/launchermanifest_nonshared/Android.mk
index 509c724..0d954e2 100644
--- a/tests/tests/shortcutmanager/packages/launchermanifest_nonshared/Android.mk
+++ b/tests/tests/shortcutmanager/packages/launchermanifest_nonshared/Android.mk
@@ -37,7 +37,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.launcher4
 
diff --git a/tests/tests/shortcutmanager/packages/packagemanifest/Android.mk b/tests/tests/shortcutmanager/packages/packagemanifest/Android.mk
index 1ece5e9..b8741f2 100644
--- a/tests/tests/shortcutmanager/packages/packagemanifest/Android.mk
+++ b/tests/tests/shortcutmanager/packages/packagemanifest/Android.mk
@@ -37,7 +37,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.package1
 
@@ -67,7 +67,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.package2
 
@@ -97,7 +97,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.package3
 
diff --git a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/Android.mk b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/Android.mk
index f87e2da..ac09355 100644
--- a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/Android.mk
+++ b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/Android.mk
@@ -37,7 +37,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_AAPT_FLAGS += --rename-manifest-package android.content.pm.cts.shortcutmanager.packages.package4
 
diff --git a/tests/tests/shortcutmanager/throttling/Android.mk b/tests/tests/shortcutmanager/throttling/Android.mk
index a3794f8..62f959e 100644
--- a/tests/tests/shortcutmanager/throttling/Android.mk
+++ b/tests/tests/shortcutmanager/throttling/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsShortcutManagerThrottlingTest
 
diff --git a/tests/tests/simpleperf/Android.mk b/tests/tests/simpleperf/Android.mk
index 80c5e55..eaec920ab 100644
--- a/tests/tests/simpleperf/Android.mk
+++ b/tests/tests/simpleperf/Android.mk
@@ -44,7 +44,7 @@
   $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY) --add-section .testzipdata=$$TMP_FILE $(linked_module) && \
   rm -f $$TMP_FILE
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_CTS_TEST_PACKAGE := android.simpleperf
 LOCAL_FORCE_STATIC_EXECUTABLE := true
diff --git a/tests/tests/simpleperf/CtsSimpleperfDebugApp/Android.mk b/tests/tests/simpleperf/CtsSimpleperfDebugApp/Android.mk
index 1fb26b7..2a172b5 100644
--- a/tests/tests/simpleperf/CtsSimpleperfDebugApp/Android.mk
+++ b/tests/tests/simpleperf/CtsSimpleperfDebugApp/Android.mk
@@ -30,6 +30,6 @@
 
 LOCAL_SDK_VERSION := current
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/speech/Android.mk b/tests/tests/speech/Android.mk
index 3995510..05f9388 100755
--- a/tests/tests/speech/Android.mk
+++ b/tests/tests/speech/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsSpeechTestCases
 
diff --git a/tests/tests/systemintents/Android.mk b/tests/tests/systemintents/Android.mk
index d75eef6..573e2ee 100644
--- a/tests/tests/systemintents/Android.mk
+++ b/tests/tests/systemintents/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/systemui/Android.mk b/tests/tests/systemui/Android.mk
index 4806f4b..4c7af5a 100644
--- a/tests/tests/systemui/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/tests/tests/telecom/Android.mk b/tests/tests/telecom/Android.mk
index 3b8b683..8a243eb 100644
--- a/tests/tests/telecom/Android.mk
+++ b/tests/tests/telecom/Android.mk
@@ -35,6 +35,6 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom2/Android.mk b/tests/tests/telecom2/Android.mk
index 5710e93..8e9c8a5d 100644
--- a/tests/tests/telecom2/Android.mk
+++ b/tests/tests/telecom2/Android.mk
@@ -49,6 +49,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom3/Android.mk b/tests/tests/telecom3/Android.mk
index a9afd31..86cb859 100644
--- a/tests/tests/telecom3/Android.mk
+++ b/tests/tests/telecom3/Android.mk
@@ -45,6 +45,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telephony/Android.mk b/tests/tests/telephony/Android.mk
index 58b6afd..1368573 100644
--- a/tests/tests/telephony/Android.mk
+++ b/tests/tests/telephony/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_PACKAGE_NAME := CtsTelephonyTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # uncomment when b/13250611 is fixed
 #LOCAL_SDK_VERSION := current
diff --git a/tests/tests/telephony/preconditions/Android.mk b/tests/tests/telephony/preconditions/Android.mk
index 1b49e7e..e2c3fc5 100644
--- a/tests/tests/telephony/preconditions/Android.mk
+++ b/tests/tests/telephony/preconditions/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MODULE := compatibility-host-telephony-preconditions
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/telephony/preconditions/app/Android.mk b/tests/tests/telephony/preconditions/app/Android.mk
index 72cbbce..a5fa396 100644
--- a/tests/tests/telephony/preconditions/app/Android.mk
+++ b/tests/tests/telephony/preconditions/app/Android.mk
@@ -32,7 +32,7 @@
                                 compatibility-device-preconditions
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsTelephonyPreparerApp
 
diff --git a/tests/tests/telephony2/Android.mk b/tests/tests/telephony2/Android.mk
index bae1dfa..ec72916 100644
--- a/tests/tests/telephony2/Android.mk
+++ b/tests/tests/telephony2/Android.mk
@@ -32,7 +32,7 @@
 LOCAL_PACKAGE_NAME := CtsTelephony2TestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_LIBRARIES += android.test.runner
 
diff --git a/tests/tests/text/Android.mk b/tests/tests/text/Android.mk
index c769bb1..15a7bcc 100644
--- a/tests/tests/text/Android.mk
+++ b/tests/tests/text/Android.mk
@@ -35,7 +35,7 @@
 LOCAL_PACKAGE_NAME := CtsTextTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # Enforce public / test api only
 LOCAL_SDK_VERSION := test_current
diff --git a/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java b/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
index 9e5d293..4d14454 100644
--- a/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
+++ b/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
@@ -17,16 +17,24 @@
 package android.text.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.InputFilter;
 import android.text.InputFilter.AllCaps;
+import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Locale;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class InputFilter_AllCapsTest {
@@ -41,7 +49,7 @@
 
         String expectedString1 = "AllCAPSTest";
         dest.insert(3, source);
-        assertEquals(expectedString1 , dest.toString());
+        assertEquals(expectedString1, dest.toString());
 
         String expectedString2 = "AllCAPSCAPS";
         dest.replace(7, 11, source);
@@ -58,4 +66,71 @@
             allCaps.filter(beforeFilterSource, 2, 7, dest, 0, beforeFilterSource.length());
         assertEquals(expectedAfterFilter, actualAfterFilter);
     }
+
+    @Test
+    public void testFilter_nonBMP() {
+        // The source string, lowerBee, is two code units that contains a single lowercase letter.
+        // DESERET SMALL LETTER BEE
+        final String lowerBee = new String(Character.toChars(0x1043A));
+        // DESERET CAPITAL LETTER BEE
+        final String upperBee = new String(Character.toChars(0x10412));
+
+        final AllCaps allCaps = new AllCaps();
+        final SpannedString dest = new SpannedString("");
+
+        // If given the whole string, the filter should transform it to uppercase.
+        assertEquals(upperBee, allCaps.filter(lowerBee, 0, lowerBee.length(), dest, 0, 0));
+
+        // If given just part of the character, it should be treated as an isolated surrogate
+        // and not get transformed, so null should be returned.
+        assertNull(allCaps.filter(lowerBee, 0, 1, dest, 0, 0));
+    }
+
+    @Test
+    public void testFilter_turkish() {
+        final String source = "i";
+        final AllCaps usAllCaps = new AllCaps(Locale.US);
+        final AllCaps turkishAllCaps = new AllCaps(new Locale("tr", "TR"));
+        final SpannedString dest = new SpannedString("");
+
+        assertEquals("I", usAllCaps.filter(source, 0, source.length(), dest, 0, 0));
+        assertEquals("İ", turkishAllCaps.filter(source, 0, source.length(), dest, 0, 0));
+    }
+
+    @Test
+    public void testFilter_titlecase() {
+        final String source = "Lj"; // U+01C8 LATIN CAPITAL LETTER L WITH SMALL LETTER J
+        final AllCaps allCaps = new AllCaps();
+        final SpannedString dest = new SpannedString("");
+
+        assertEquals("LJ", // LATIN CAPITAL LETTER LJ
+                allCaps.filter(source, 0, source.length(), dest, 0, 0));
+    }
+
+    @Test
+    public void testFilter_greekWithSpans() {
+        final Locale greek = new Locale("el", "GR");
+        final String lowerString = "ι\u0301ριδα";  // ίριδα with first letter decomposed
+        final String upperString = "ΙΡΙΔΑ";  // uppercased
+
+        final SpannableString source = new SpannableString(lowerString);
+        final Object span = new Object();
+        source.setSpan(span, 0, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE); // around "ί"
+
+        final AllCaps greekAllCaps = new AllCaps(greek);
+        final SpannedString dest = new SpannedString("");
+        final CharSequence result = greekAllCaps.filter(source, 0, source.length(), dest, 0, 0);
+
+        assertEquals(upperString, result.toString());
+        assertTrue(result instanceof Spanned);
+        final Spanned spannedResult = (Spanned) result;
+        final Object[] resultSpans = spannedResult.getSpans(
+                0, spannedResult.length(), Object.class);
+        assertEquals(1, resultSpans.length);
+        assertSame(span, resultSpans[0]);
+        assertEquals(0, spannedResult.getSpanStart(span));
+        // The two characters in source have been transformed to one character in the result.
+        assertEquals(1, spannedResult.getSpanEnd(span));
+        assertEquals(Spanned.SPAN_INCLUSIVE_INCLUSIVE, spannedResult.getSpanFlags(span));
+    }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java b/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java
index aa4ccdd..125b773 100644
--- a/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java
@@ -16,12 +16,16 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.StaticLayout;
 import android.text.TextPaint;
 import android.text.style.StrikethroughSpan;
 
@@ -88,4 +92,25 @@
             p.recycle();
         }
     }
+
+    // Measures the width of some potentially-spanned text, assuming it's not too wide.
+    private float textWidth(CharSequence text) {
+        final TextPaint tp = new TextPaint();
+        tp.setTextSize(100.0f); // Large enough so that the difference in kerning is visible.
+        final int largeWidth = 10000; // Enough width so the whole text fits in one line.
+        final StaticLayout layout = StaticLayout.Builder.obtain(
+                text, 0, text.length(), tp, largeWidth).build();
+        return layout.getLineWidth(0);
+    }
+
+    @Test
+    public void testDoesntAffectWidth() {
+        // Roboto kerns between "P" and "."
+        final SpannableString text = new SpannableString("P.");
+        final float origLineWidth = textWidth(text);
+        // Strike through just the "P".
+        text.setSpan(new StrikethroughSpan(), 0, 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        final float strokethroughLineWidth = textWidth(text);
+        assertEquals(origLineWidth, strokethroughLineWidth, 0.0f);
+    }
 }
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index 59c6ef4..ec88500 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -25,6 +25,7 @@
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.telephony.TelephonyManager;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.style.URLSpan;
@@ -353,10 +354,15 @@
                 + " " + numbersUSLocal
                 + " " + numbersIntl);
 
-        // phonenumber linkify is locale-dependent
-        if (Locale.US.equals(Locale.getDefault())) {
-            assertTrue(Linkify.addLinks(spannable, Linkify.PHONE_NUMBERS));
-            URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        // phonenumber linkify depends on the device's SIM card country.
+        final TelephonyManager tm =
+                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        final String region = tm.getSimCountryIso().toUpperCase(Locale.US);
+
+        assertTrue(Linkify.addLinks(spannable, Linkify.PHONE_NUMBERS));
+        final URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        if ("US".equals(region)) {
+            // For the US, these specific phone numbers should be detected.
             assertEquals(9, spans.length);
             assertEquals("tel:8121234562", spans[0].getURL());
             assertEquals("tel:8121234563", spans[1].getURL());
@@ -367,6 +373,16 @@
             assertEquals("tel:+4408121234565", spans[6].getURL());
             assertEquals("tel:+18005551213", spans[7].getURL());
             assertEquals("tel:+18005551214", spans[8].getURL());
+        } else {
+            // For other countries, the phone numbers that would be detected are based on the
+            // country, so the exact list is unknown, but the various international phone numbers,
+            // starting with '+', must always be detected, and must appear next to each other and
+            // at the end of the list.
+            assertTrue(spans.length >= 4);
+            assertEquals("tel:+4408121234564", spans[spans.length - 4].getURL());
+            assertEquals("tel:+4408121234565", spans[spans.length - 3].getURL());
+            assertEquals("tel:+18005551213", spans[spans.length - 2].getURL());
+            assertEquals("tel:+18005551214", spans[spans.length - 1].getURL());
         }
 
         assertFalse(Linkify.addLinks((Spannable) null, 0));
diff --git a/tests/tests/theme/Android.mk b/tests/tests/theme/Android.mk
index 365f198..71d576d 100644
--- a/tests/tests/theme/Android.mk
+++ b/tests/tests/theme/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/toast/Android.mk b/tests/tests/toast/Android.mk
index cb8fe99..1ba7d79 100644
--- a/tests/tests/toast/Android.mk
+++ b/tests/tests/toast/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
diff --git a/tests/tests/toastlegacy/Android.mk b/tests/tests/toastlegacy/Android.mk
index 96916a3..335c539 100644
--- a/tests/tests/toastlegacy/Android.mk
+++ b/tests/tests/toastlegacy/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
diff --git a/tests/tests/transition/Android.mk b/tests/tests/transition/Android.mk
index 875f58c..1c171eb 100644
--- a/tests/tests/transition/Android.mk
+++ b/tests/tests/transition/Android.mk
@@ -38,6 +38,6 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/tv/Android.mk b/tests/tests/tv/Android.mk
index 66b35a1..30429d3 100644
--- a/tests/tests/tv/Android.mk
+++ b/tests/tests/tv/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index 0a7f86d..27c388a 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -1431,29 +1431,41 @@
         final Uri CHANNEL_URI_FOR_PASSTHROUGH_INPUT =
                 TvContract.buildChannelUriForPassthroughInput("inputId");
         final Uri PROGRAM_URI = TvContract.buildProgramUri(0);
+        final Uri RECORDED_PROGRAM_URI = TvContract.buildRecordedProgramUri(0);
 
         // Test isChannelUri
         assertTrue(TvContract.isChannelUri(CHANNEL_URI_FOR_TUNER));
         assertTrue(TvContract.isChannelUri(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertFalse(TvContract.isChannelUri(PROGRAM_URI));
+        assertFalse(TvContract.isChannelUri(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isChannelUri(null));
 
         // Test isChannelUriForPassthroughInput
         assertFalse(TvContract.isChannelUriForPassthroughInput(CHANNEL_URI_FOR_TUNER));
         assertTrue(TvContract.isChannelUriForPassthroughInput(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertFalse(TvContract.isChannelUriForPassthroughInput(PROGRAM_URI));
+        assertFalse(TvContract.isChannelUriForPassthroughInput(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isChannelUriForPassthroughInput(null));
 
         // Test isChannelUriForTunerInput
         assertTrue(TvContract.isChannelUriForTunerInput(CHANNEL_URI_FOR_TUNER));
         assertFalse(TvContract.isChannelUriForTunerInput(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertFalse(TvContract.isChannelUriForTunerInput(PROGRAM_URI));
+        assertFalse(TvContract.isChannelUriForTunerInput(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isChannelUriForTunerInput(null));
 
         // Test isProgramUri
         assertFalse(TvContract.isProgramUri(CHANNEL_URI_FOR_TUNER));
         assertFalse(TvContract.isProgramUri(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertTrue(TvContract.isProgramUri(PROGRAM_URI));
+        assertFalse(TvContract.isProgramUri(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isProgramUri(null));
+
+        // Test isRecordedProgramUri
+        assertFalse(TvContract.isRecordedProgramUri(CHANNEL_URI_FOR_TUNER));
+        assertFalse(TvContract.isRecordedProgramUri(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
+        assertFalse(TvContract.isRecordedProgramUri(PROGRAM_URI));
+        assertTrue(TvContract.isRecordedProgramUri(RECORDED_PROGRAM_URI));
+        assertFalse(TvContract.isRecordedProgramUri(null));
     }
 }
diff --git a/tests/tests/uiautomation/Android.mk b/tests/tests/uiautomation/Android.mk
index d708c67..eb6ed68 100644
--- a/tests/tests/uiautomation/Android.mk
+++ b/tests/tests/uiautomation/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ub-uiautomator legacy-android-test
 
diff --git a/tests/tests/uidisolation/Android.mk b/tests/tests/uidisolation/Android.mk
index a69de23..e9ee3e9 100644
--- a/tests/tests/uidisolation/Android.mk
+++ b/tests/tests/uidisolation/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctstestserver legacy-android-test
 
diff --git a/tests/tests/uirendering/Android.mk b/tests/tests/uirendering/Android.mk
index 06bd748..7d99b57 100644
--- a/tests/tests/uirendering/Android.mk
+++ b/tests/tests/uirendering/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/tests/tests/uirendering/assets/wide-gamut-test.png b/tests/tests/uirendering/assets/wide-gamut-test.png
new file mode 100644
index 0000000..ba8dbcf
--- /dev/null
+++ b/tests/tests/uirendering/assets/wide-gamut-test.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/bitmap_density.xml b/tests/tests/uirendering/res/drawable/bitmap_density.xml
similarity index 92%
rename from tests/tests/graphics/res/drawable/bitmap_density.xml
rename to tests/tests/uirendering/res/drawable/bitmap_density.xml
index 5fb3611..04d6125 100644
--- a/tests/tests/graphics/res/drawable/bitmap_density.xml
+++ b/tests/tests/uirendering/res/drawable/bitmap_density.xml
@@ -16,4 +16,4 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/bitmap_density_internal" />
+        android:src="@drawable/icon_blue" />
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_am_density.xml b/tests/tests/uirendering/res/drawable/bitmap_shader_am_density.xml
similarity index 92%
rename from tests/tests/graphics/res/drawable/bitmap_shader_am_density.xml
rename to tests/tests/uirendering/res/drawable/bitmap_shader_am_density.xml
index dfecfbb..9c28199 100644
--- a/tests/tests/graphics/res/drawable/bitmap_shader_am_density.xml
+++ b/tests/tests/uirendering/res/drawable/bitmap_shader_am_density.xml
@@ -16,7 +16,7 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/bitmap_shader_density_internal"
+        android:src="@drawable/icon_blue"
         android:tileModeX="repeat"
         android:tileModeY="clamp"
         android:autoMirrored="true" />
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_density.xml b/tests/tests/uirendering/res/drawable/bitmap_shader_density.xml
similarity index 92%
rename from tests/tests/graphics/res/drawable/bitmap_shader_density.xml
rename to tests/tests/uirendering/res/drawable/bitmap_shader_density.xml
index 435b06a..216874e 100644
--- a/tests/tests/graphics/res/drawable/bitmap_shader_density.xml
+++ b/tests/tests/uirendering/res/drawable/bitmap_shader_density.xml
@@ -16,6 +16,6 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/bitmap_shader_density_internal"
+        android:src="@drawable/icon_blue"
         android:tileModeX="repeat"
         android:tileModeY="clamp" />
diff --git a/tests/tests/uirendering/res/drawable/icon_blue.jpg b/tests/tests/uirendering/res/drawable/icon_blue.jpg
new file mode 100644
index 0000000..9e6c1c8
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable/icon_blue.jpg
Binary files differ
diff --git a/tests/tests/uirendering/res/layout/wide_gamut_bitmap_layout.xml b/tests/tests/uirendering/res/layout/wide_gamut_bitmap_layout.xml
new file mode 100644
index 0000000..adc436a
--- /dev/null
+++ b/tests/tests/uirendering/res/layout/wide_gamut_bitmap_layout.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<android.uirendering.cts.testclasses.view.BitmapView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content" />
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/BitmapVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/BitmapVerifier.java
index 2f7acd5..61767b3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/BitmapVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/BitmapVerifier.java
@@ -27,6 +27,14 @@
 
     protected Bitmap mDifferenceBitmap;
 
+    public boolean verify(Bitmap bitmap) {
+        int width = bitmap.getWidth();
+        int height = bitmap.getHeight();
+        int[] pixels = new int[width * height];
+        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+        return verify(pixels, 0, width, width, height);
+    }
+
     /**
      * This will test if the bitmap is good or not.
      */
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointWideGamutVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointWideGamutVerifier.java
new file mode 100644
index 0000000..c075105
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointWideGamutVerifier.java
@@ -0,0 +1,71 @@
+/*
+ * 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.uirendering.cts.bitmapverifiers;
+
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
+import android.util.Half;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+
+public class SamplePointWideGamutVerifier extends WideGamutBitmapVerifier {
+    private static final String TAG = "SamplePointWideGamut";
+
+    private static final ColorSpace SCRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+
+    private final Point[] mPoints;
+    private final Color[] mColors;
+    private final float mEps;
+
+    public SamplePointWideGamutVerifier(Point[] points, Color[] colors, float eps) {
+        mPoints = points;
+        mColors = colors;
+        mEps = eps;
+    }
+
+    @Override
+    public boolean verify(ByteBuffer bitmap, int offset, int stride, int width, int height) {
+        boolean success = true;
+        for (int i = 0; i < mPoints.length; i++) {
+            Point p = mPoints[i];
+            Color c = mColors[i];
+
+            int index = p.y * stride + (p.x << 3);
+            float r = Half.toFloat(bitmap.getShort(index));
+            float g = Half.toFloat(bitmap.getShort(index + 2));
+            float b = Half.toFloat(bitmap.getShort(index + 4));
+
+            boolean localSuccess = true;
+            if (!floatCompare(c.red(),   r, mEps)) localSuccess = false;
+            if (!floatCompare(c.green(), g, mEps)) localSuccess = false;
+            if (!floatCompare(c.blue(),  b, mEps)) localSuccess = false;
+
+            if (!localSuccess) {
+                success = false;
+                Log.w(TAG, "Expected " + c.toString() + " at " + p.x + "x" + p.y
+                        + ", got " + Color.valueOf(r, g, b, 1.0f, SCRGB).toString());
+            }
+        }
+        return success;
+    }
+
+    private static boolean floatCompare(float a, float b, float eps) {
+        return Float.compare(a, b) == 0 || Math.abs(a - b) <= eps;
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/WideGamutBitmapVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/WideGamutBitmapVerifier.java
new file mode 100644
index 0000000..0c11a064
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/WideGamutBitmapVerifier.java
@@ -0,0 +1,46 @@
+/*
+ * 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.uirendering.cts.bitmapverifiers;
+
+import android.graphics.Bitmap;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public abstract class WideGamutBitmapVerifier extends BitmapVerifier {
+    @Override
+    public boolean verify(Bitmap bitmap) {
+        ByteBuffer dst = ByteBuffer.allocateDirect(bitmap.getAllocationByteCount());
+        bitmap.copyPixelsToBuffer(dst);
+        dst.rewind();
+        dst.order(ByteOrder.LITTLE_ENDIAN);
+
+        int width = bitmap.getWidth();
+        int height = bitmap.getHeight();
+        return verify(dst, 0, bitmap.getRowBytes(), width, height);
+    }
+
+    public abstract boolean verify(ByteBuffer bitmap, int offset, int stride,
+            int width, int height);
+
+    @Override
+    public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
+        // This method is never called, we use
+        // verify(ByteBuffer bitmap, int offset, int stride, int width, int height) instead
+        return false;
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapDrawableTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapDrawableTest.java
new file mode 100644
index 0000000..7b01d34
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapDrawableTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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 android.uirendering.cts.testclasses;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.res.Resources.Theme;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Drawable.ConstantState;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapverifiers.RectVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.CanvasClient;
+import android.util.LayoutDirection;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BitmapDrawableTest extends ActivityTestBase {
+
+    // The target context.
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    private static final int[] DENSITY_VALUES = new int[] {
+            160, 80, 320
+    };
+
+    private static final int[] DENSITY_IMAGES = new int[] {
+            R.drawable.bitmap_density,
+            R.drawable.bitmap_shader_density,
+            R.drawable.bitmap_shader_am_density,
+    };
+
+    @Test
+    public void testPreloadDensity() throws IOException {
+        final Resources res = mContext.getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+        try {
+            for (int i = 0; i < DENSITY_IMAGES.length; i++) {
+                verifyPreloadDensityInner(res, DENSITY_IMAGES[i], DENSITY_VALUES);
+            }
+        } finally {
+            setResourcesDensity(res, densityDpi);
+        }
+    }
+
+    private void verifyPreloadDensityInner(Resources res, int sourceResId, int[] densities)
+            throws IOException {
+        final Rect tempPadding = new Rect();
+
+        // Capture initial state at preload density.
+        final int preloadDensityDpi = densities[0];
+        setResourcesDensity(res, preloadDensityDpi);
+
+        final BitmapDrawable preloadedDrawable = (BitmapDrawable) res.getDrawable(sourceResId);
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        final int origWidth = preloadedDrawable.getIntrinsicWidth();
+        final int origHeight = preloadedDrawable.getIntrinsicHeight();
+        assertFalse(preloadedDrawable.getPadding(tempPadding));
+
+        runTest(preloadedDrawable);
+
+        for (int i = 1; i < densities.length; i++) {
+            final int scaledDensityDpi = densities[i];
+            final float scale = scaledDensityDpi / (float) preloadDensityDpi;
+            setResourcesDensity(res, scaledDensityDpi);
+
+            final BitmapDrawable scaledDrawable =
+                    (BitmapDrawable) preloadedConstantState.newDrawable(res);
+            scaledDrawable.setLayoutDirection(LayoutDirection.RTL);
+
+            // Sizes are rounded.
+            assertEquals(Math.round(origWidth * scale), scaledDrawable.getIntrinsicWidth());
+            assertEquals(Math.round(origHeight * scale), scaledDrawable.getIntrinsicHeight());
+
+            // Bitmaps have no padding.
+            assertFalse(scaledDrawable.getPadding(tempPadding));
+
+            runTest(scaledDrawable);
+
+            // Ensure theme density is applied correctly. Unlike most
+            // drawables, we don't have any loss of accuracy because density
+            // changes are re-computed from the source every time.
+            setResourcesDensity(res, preloadDensityDpi);
+
+            final Theme t = res.newTheme();
+            scaledDrawable.applyTheme(t);
+            assertEquals(origWidth, scaledDrawable.getIntrinsicWidth());
+            assertEquals(origHeight, scaledDrawable.getIntrinsicHeight());
+            assertFalse(scaledDrawable.getPadding(tempPadding));
+        }
+    }
+
+    private void runTest(Drawable dr) {
+        final Rect drBounds = new Rect(0, 0, dr.getIntrinsicWidth(), dr.getIntrinsicHeight());
+        CanvasClient canvasClient = (canvas, width, height) -> {
+            assertTrue(width > drBounds.width());
+            assertTrue(height > drBounds.height());
+            dr.setBounds(drBounds);
+            dr.draw(canvas);
+        };
+        createTest()
+                .addCanvasClient(canvasClient)
+                .runWithVerifier(new RectVerifier(Color.WHITE, Color.BLUE, drBounds));
+    }
+
+    private static void setResourcesDensity(Resources res, int densityDpi) {
+        final Configuration config = new Configuration();
+        config.setTo(res.getConfiguration());
+        config.densityDpi = densityDpi;
+        res.updateConfiguration(config, null);
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
index 1ff74bf..0763e4b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
@@ -109,11 +109,6 @@
     }
 
     @Test
-    public void testBitmapConfigFromIndex8() {
-        testBitmapCopy(R.drawable.index_8, null, Bitmap.Config.HARDWARE);
-    }
-
-    @Test
     public void testBitmapConfigFromHardwareToHardware() {
         testBitmapCopy(R.drawable.robot, Bitmap.Config.HARDWARE, Bitmap.Config.HARDWARE);
     }
@@ -247,4 +242,4 @@
             canvas.drawBitmap(copy, 0, 0, null);
         }, true).runWithComparer(new MSSIMComparer(0.99));
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/WideColorGamutTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/WideColorGamutTests.java
new file mode 100644
index 0000000..9f46e36
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/WideColorGamutTests.java
@@ -0,0 +1,132 @@
+/*
+ * 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.uirendering.cts.testclasses;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
+import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
+import android.uirendering.cts.bitmapverifiers.SamplePointWideGamutVerifier;
+import android.uirendering.cts.testclasses.view.BitmapView;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.view.View;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WideColorGamutTests extends ActivityTestBase {
+    private static final ColorSpace DISPLAY_P3 = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+    private static final ColorSpace SCRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+
+    private static final Point[] POINTS = {
+            new Point(16, 16),
+            new Point(48, 16),
+            new Point(80, 16),
+    };
+
+    // The colors are defined as found in wide-gamut-test.png, which is Display P3
+    // Since the UI toolkit renders in scRGB, we want to convert here to compare values
+    // directly in the sample point verifier
+    private static final Color[] COLORS = {
+            Color.valueOf(0.937f, 0.000f, 0.000f, 1.0f, DISPLAY_P3).convert(SCRGB),
+            Color.valueOf(1.000f, 0.000f, 0.000f, 1.0f, DISPLAY_P3).convert(SCRGB),
+            Color.valueOf(0.918f, 0.200f, 0.137f, 1.0f, DISPLAY_P3).convert(SCRGB)
+    };
+
+    private Bitmap mBitmap;
+
+    @Override
+    protected boolean isWideColorGamut() {
+        return true;
+    }
+
+    @Before
+    public void loadBitmap() {
+        try (InputStream in = getActivity().getAssets().open("wide-gamut-test.png")) {
+            mBitmap = BitmapFactory.decodeStream(in);
+        } catch (IOException e) {
+            Assert.fail("Could not load wide-gamut-test.png");
+        }
+    }
+
+    @SuppressWarnings("SameParameterValue")
+    private BitmapVerifier getVerifier(Point[] points, Color[] colors, float eps) {
+        if (getActivity().getWindow().isWideColorGamut()) {
+            return new SamplePointWideGamutVerifier(points, colors, eps);
+        }
+        return new SamplePointVerifier(points,
+                Arrays.stream(colors).mapToInt(Color::toArgb).toArray(),
+                (int) (eps * 255.0f + 0.5f));
+    }
+
+    @Test
+    public void testDraw() {
+        createTest()
+                .addLayout(R.layout.wide_gamut_bitmap_layout, view -> {
+                    BitmapView bv = (BitmapView) view;
+                    bv.setBitmap(mBitmap);
+                }, true)
+                .runWithVerifier(getVerifier(POINTS, COLORS, 1e-2f));
+    }
+
+    @Test
+    public void testSaveLayer() {
+        createTest()
+                .addLayout(R.layout.wide_gamut_bitmap_layout, view -> {
+                    BitmapView bv = (BitmapView) view;
+                    bv.setBitmap(mBitmap);
+                    bv.setSaveLayer(true);
+                }, true)
+                .runWithVerifier(getVerifier(POINTS, COLORS, 1e-2f));
+    }
+
+    @Test
+    public void testHardwareLayer() {
+        createTest()
+                .addLayout(R.layout.wide_gamut_bitmap_layout, view -> {
+                    BitmapView bv = (BitmapView) view;
+                    bv.setBitmap(mBitmap);
+                    bv.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                }, true)
+                .runWithVerifier(getVerifier(POINTS, COLORS, 1e-2f));
+    }
+
+    @Test
+    public void testSaveLayerInHardwareLayer() {
+        createTest()
+                .addLayout(R.layout.wide_gamut_bitmap_layout, view -> {
+                    BitmapView bv = (BitmapView) view;
+                    bv.setBitmap(mBitmap);
+                    bv.setSaveLayer(true);
+                    bv.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                }, true)
+                .runWithVerifier(getVerifier(POINTS, COLORS, 1e-2f));
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/BitmapView.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/BitmapView.java
new file mode 100644
index 0000000..b672e40
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/BitmapView.java
@@ -0,0 +1,81 @@
+/*
+ * 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.uirendering.cts.testclasses.view;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class BitmapView extends View {
+    private Bitmap mBitmap;
+    private boolean mSaveLayer;
+
+    public BitmapView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public BitmapView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public BitmapView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public BitmapView(Context context, Bitmap b, boolean saveLayer) {
+        super(context);
+        mBitmap = b;
+        mSaveLayer = saveLayer;
+    }
+
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
+    public void setBitmap(Bitmap bitmap) {
+        mBitmap = bitmap;
+    }
+
+    public boolean isSaveLayer() {
+        return mSaveLayer;
+    }
+
+    public void setSaveLayer(boolean saveLayer) {
+        mSaveLayer = saveLayer;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (mSaveLayer) {
+            canvas.saveLayer(0.0f, 0.0f, getWidth(), getHeight(), null);
+        }
+        canvas.drawBitmap(mBitmap, 0, 0, null);
+        if (mSaveLayer) {
+            canvas.restore();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index d6a196a..6fe44c3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -82,11 +82,16 @@
             Intent intent = new Intent(Intent.ACTION_MAIN);
             intent.setClass(instrumentation.getTargetContext(), DrawActivity.class);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            intent.putExtra(DrawActivity.EXTRA_WIDE_COLOR_GAMUT, isWideColorGamut());
             sActivity = (DrawActivity) instrumentation.startActivitySync(intent);
         }
         return sActivity;
     }
 
+    protected boolean isWideColorGamut() {
+        return false;
+    }
+
     @AfterClass
     public static void tearDownClass() {
         if (sActivity != null) {
@@ -124,7 +129,9 @@
         if (mScreenshotter == null) {
             SynchronousPixelCopy copy = new SynchronousPixelCopy();
             Bitmap dest = Bitmap.createBitmap(
-                    TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
+                    TEST_WIDTH, TEST_HEIGHT,
+                    getActivity().getWindow().isWideColorGamut()
+                            ? Config.RGBA_F16 : Config.ARGB_8888);
             Rect srcRect = new Rect(testOffset.x, testOffset.y,
                     testOffset.x + TEST_WIDTH, testOffset.y + TEST_HEIGHT);
             Log.d("UiRendering", "capturing screenshot of " + srcRect.toShortString());
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index 9820ab2..22f3158 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.fail;
 
 import android.app.Activity;
+import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.os.Bundle;
@@ -41,6 +42,8 @@
  * A generic activity that uses a view specified by the user.
  */
 public class DrawActivity extends Activity {
+    static final String EXTRA_WIDE_COLOR_GAMUT = "DrawActivity.WIDE_COLOR_GAMUT";
+
     private final static long TIME_OUT_MS = 10000;
     private final Point mLock = new Point();
 
@@ -53,6 +56,9 @@
         super.onCreate(bundle);
         getWindow().getDecorView().setSystemUiVisibility(
                 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
+        if (getIntent().getBooleanExtra(EXTRA_WIDE_COLOR_GAMUT, false)) {
+            getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
+        }
         mHandler = new RenderSpecHandler();
         int uiMode = getResources().getConfiguration().uiMode;
         mOnTv = (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
index d5f9324..1523283 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
@@ -83,9 +83,7 @@
             String testName, String debugMessage) {
         int width = bitmap.getWidth();
         int height = bitmap.getHeight();
-        int[] pixels = new int[width * height];
-        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
-        boolean success = bitmapVerifier.verify(pixels, 0, width, width, height);
+        boolean success = bitmapVerifier.verify(bitmap);
         if (!success) {
             Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
             BitmapDumper.dumpBitmap(croppedBitmap, testName, mClassName);
diff --git a/tests/tests/util/Android.mk b/tests/tests/util/Android.mk
index 3ceeadd..ed7a61c 100644
--- a/tests/tests/util/Android.mk
+++ b/tests/tests/util/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-annotations \
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index a50b42f..f67ba7a 100644
--- a/tests/tests/view/Android.mk
+++ b/tests/tests/view/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_MULTILIB := both
 
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 5d23183..7af3b42 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -175,6 +175,7 @@
                   android:screenOrientation="locked"
                   android:label="PixelCopyGLProducerCtsActivity"/>
 
+
         <activity android:name="android.view.cts.PixelCopyViewProducerActivity"
                   android:label="PixelCopyViewProducerActivity"
                   android:screenOrientation="portrait"
@@ -182,6 +183,14 @@
                   android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
                   android:configChanges="orientation|screenSize" />
 
+        <activity android:name="android.view.cts.PixelCopyWideGamutViewProducerActivity"
+                  android:label="PixelCopyWideGamutViewProducerActivity"
+                  android:screenOrientation="portrait"
+                  android:rotationAnimation="jumpcut"
+                  android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
+                  android:configChanges="orientation|screenSize"
+                  android:colorMode="wideColorGamut" />
+
         <activity android:name="android.view.cts.FocusFinderCtsActivity"
                   android:screenOrientation="locked"
                   android:label="FocusFinderCtsActivity">
diff --git a/tests/tests/view/assets/prophoto.png b/tests/tests/view/assets/prophoto.png
new file mode 100644
index 0000000..8badba7
--- /dev/null
+++ b/tests/tests/view/assets/prophoto.png
Binary files differ
diff --git a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml b/tests/tests/view/res/drawable/scrollbar_no_size.xml
similarity index 80%
copy from tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
copy to tests/tests/view/res/drawable/scrollbar_no_size.xml
index 173435b..88a59f0 100644
--- a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
+++ b/tests/tests/view/res/drawable/scrollbar_no_size.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 
-<paths xmlns:android="http://schemas.android.com/apk/res/android">
-    <files-path name="apk" path="/" />
-</paths>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@android:color/white" />
+</shape>
diff --git a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml b/tests/tests/view/res/drawable/scrollbar_thumb.xml
similarity index 70%
copy from tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
copy to tests/tests/view/res/drawable/scrollbar_thumb.xml
index 173435b..d7612ac 100644
--- a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
+++ b/tests/tests/view/res/drawable/scrollbar_thumb.xml
@@ -14,6 +14,10 @@
      limitations under the License.
 -->
 
-<paths xmlns:android="http://schemas.android.com/apk/res/android">
-    <files-path name="apk" path="/" />
-</paths>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@android:color/white" />
+    <size
+        android:width="@dimen/scrollbar_thumb_width"
+        android:height="@dimen/scrollbar_thumb_height"/>
+</shape>
diff --git a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml b/tests/tests/view/res/drawable/scrollbar_track.xml
similarity index 70%
copy from tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
copy to tests/tests/view/res/drawable/scrollbar_track.xml
index 173435b..a184569 100644
--- a/tests/tests/packageinstaller/externalsources/res/xml/file_paths.xml
+++ b/tests/tests/view/res/drawable/scrollbar_track.xml
@@ -14,6 +14,10 @@
      limitations under the License.
 -->
 
-<paths xmlns:android="http://schemas.android.com/apk/res/android">
-    <files-path name="apk" path="/" />
-</paths>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@android:color/white" />
+    <size
+        android:width="@dimen/scrollbar_track_width"
+        android:height="@dimen/scrollbar_track_height"/>
+</shape>
diff --git a/tests/tests/view/res/layout/view_layout.xml b/tests/tests/view/res/layout/view_layout.xml
index 920da83..3cfaafa 100644
--- a/tests/tests/view/res/layout/view_layout.xml
+++ b/tests/tests/view/res/layout/view_layout.xml
@@ -46,6 +46,42 @@
         android:requiresFadingEdge="horizontal|vertical"
         android:fadingEdgeLength="20px"/>
 
+    <android.view.cts.MockView
+        android:id="@+id/scroll_view_3"
+        android:layout_width="100px"
+        android:layout_height="200px"
+        android:scrollbars="horizontal|vertical"
+        android:scrollbarThumbVertical="@drawable/scrollbar_no_size"
+        android:scrollbarThumbHorizontal="@drawable/scrollbar_no_size"/>
+
+    <android.view.cts.MockView
+        android:id="@+id/scroll_view_4"
+        android:layout_width="100px"
+        android:layout_height="200px"
+        android:scrollbars="horizontal|vertical"
+        android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
+        android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"/>
+
+    <android.view.cts.MockView
+        android:id="@+id/scroll_view_5"
+        android:layout_width="100px"
+        android:layout_height="200px"
+        android:scrollbars="horizontal|vertical"
+        android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
+        android:scrollbarTrackVertical="@drawable/scrollbar_track"
+        android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"
+        android:scrollbarTrackHorizontal="@drawable/scrollbar_track"/>
+
+    <android.view.cts.MockView
+        android:id="@+id/scroll_view_6"
+        android:layout_width="100px"
+        android:layout_height="200px"
+        android:scrollbars="horizontal|vertical"
+        android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
+        android:scrollbarTrackVertical="@drawable/scrollbar_no_size"
+        android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"
+        android:scrollbarTrackHorizontal="@drawable/scrollbar_no_size"/>
+
     <View
         android:id="@+id/fit_windows"
         android:fitsSystemWindows="true"
diff --git a/tests/tests/view/res/values/dimens.xml b/tests/tests/view/res/values/dimens.xml
index 5680de0..5ae23c2 100644
--- a/tests/tests/view/res/values/dimens.xml
+++ b/tests/tests/view/res/values/dimens.xml
@@ -41,4 +41,8 @@
     <dimen name="hover_target_margin">4dp</dimen>
     <dimen name="hover_target_size">8dp</dimen>
     <dimen name="hover_target_size_double">16dp</dimen>
+    <dimen name="scrollbar_thumb_width">11dp</dimen>
+    <dimen name="scrollbar_thumb_height">12dp</dimen>
+    <dimen name="scrollbar_track_width">13dp</dimen>
+    <dimen name="scrollbar_track_height">14dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java b/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
index 6c95e1f..145436b 100644
--- a/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
+++ b/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
@@ -19,6 +19,8 @@
 import static org.junit.Assert.fail;
 
 import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -26,7 +28,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@SmallTest
+@FlakyTest
 @RunWith(AndroidJUnit4.class)
 public class ChoreographerNativeTest {
     private long mChoreographerPtr;
@@ -49,11 +51,13 @@
         }
     }
 
+    @MediumTest
     @Test
     public void testPostCallbackWithoutDelayEventuallyRunsCallbacks() {
         nativeTestPostCallbackWithoutDelayEventuallyRunsCallbacks(mChoreographerPtr);
     }
 
+    @SmallTest
     @Test
     public void testPostCallbackWithDelayEventuallyRunsCallbacks() {
         nativeTestPostCallbackWithDelayEventuallyRunsCallbacks(mChoreographerPtr);
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index a8015ab..d3deb92 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -386,8 +386,8 @@
         FrameLayout layout = new FrameLayout(mLayout.getContext());
         Button button1 = new Button(mLayout.getContext());
         Button button2 = new Button(mLayout.getContext());
-        button1.setLeftTopRightBottom(0, 0, 10, 10);
-        button2.setLeftTopRightBottom(0, 0, 10, 10);
+        setViewBox(button1, 0, 0, 10, 10);
+        setViewBox(button2, 0, 0, 10, 10);
         layout.addView(button1);
         layout.addView(button2);
         View[] views = new View[]{button2, button1};
@@ -401,7 +401,7 @@
         assertEquals(button2, views[0]);
         assertEquals(button1, views[1]);
         // make sure it will actually mutate input array.
-        button2.setLeftTopRightBottom(20, 0, 30, 10);
+        setViewBox(button2, 20, 0, 30, 10);
         FocusFinder.sort(views, 0, 2, layout, false);
         assertEquals(button1, views[0]);
         assertEquals(button2, views[1]);
@@ -428,4 +428,11 @@
         verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
         verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mBottomRight);
     }
+
+    private void setViewBox(View view, int left, int top, int right, int bottom) {
+        view.setLeft(left);
+        view.setTop(top);
+        view.setRight(right);
+        view.setBottom(bottom);
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index 6310ce8..0cbd0ca 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -17,6 +17,7 @@
 package android.view.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -24,6 +25,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Instrumentation;
+import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Color;
@@ -36,6 +38,7 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.Half;
 import android.util.Log;
 import android.view.PixelCopy;
 import android.view.Surface;
@@ -52,6 +55,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.model.Statement;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -73,6 +78,11 @@
             new ActivityTestRule<>(PixelCopyViewProducerActivity.class, false, false);
 
     @Rule
+    public ActivityTestRule<PixelCopyWideGamutViewProducerActivity>
+            mWideGamutWindowSourceActivityRule = new ActivityTestRule<>(
+                    PixelCopyWideGamutViewProducerActivity.class, false, false);
+
+    @Rule
     public SurfaceTextureRule mSurfaceRule = new SurfaceTextureRule();
 
     private Instrumentation mInstrumentation;
@@ -231,6 +241,30 @@
                 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
     }
 
+    @Test
+    public void testReuseBitmap() {
+        // Since we only sample mid-pixel of each qudrant, filtering
+        // quality isn't tested
+        PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888);
+        int result = mCopyHelper.request(activity.getView(), bitmap);
+        // Make sure nothing messed with the bitmap
+        assertEquals(20, bitmap.getWidth());
+        assertEquals(20, bitmap.getHeight());
+        assertEquals(Config.ARGB_8888, bitmap.getConfig());
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+        int generationId = bitmap.getGenerationId();
+        result = mCopyHelper.request(activity.getView(), bitmap);
+        // Make sure nothing messed with the bitmap
+        assertEquals(20, bitmap.getWidth());
+        assertEquals(20, bitmap.getHeight());
+        assertEquals(Config.ARGB_8888, bitmap.getConfig());
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+        assertNotEquals(generationId, bitmap.getGenerationId());
+    }
+
     private Window waitForWindowProducerActivity() {
         PixelCopyViewProducerActivity activity =
                 mWindowSourceActivityRule.launchActivity(null);
@@ -319,6 +353,125 @@
         } while (activity.rotate());
     }
 
+    @Test
+    public void testWindowProducerCopyToRGBA16F() {
+        Window window = waitForWindowProducerActivity();
+        PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity();
+
+        Bitmap bitmap;
+        do {
+            Rect src = makeWindowRect(0, 0, 100, 100);
+            bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16);
+            int result = mCopyHelper.request(window, src, bitmap);
+            // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's
+            // not support for float textures
+            if (result != PixelCopy.ERROR_DESTINATION_INVALID) {
+                assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+                assertEquals(Config.RGBA_F16, bitmap.getConfig());
+                assertBitmapQuadColor(bitmap,
+                        Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+                assertBitmapEdgeColor(bitmap, Color.YELLOW);
+            }
+        } while (activity.rotate());
+    }
+
+    private Window waitForWideGamutWindowProducerActivity() {
+        PixelCopyWideGamutViewProducerActivity activity =
+                mWideGamutWindowSourceActivityRule.launchActivity(null);
+        activity.waitForFirstDrawCompleted(3, TimeUnit.SECONDS);
+        return activity.getWindow();
+    }
+
+    private Rect makeWideGamutWindowRect(int left, int top, int right, int bottom) {
+        Rect r = new Rect(left, top, right, bottom);
+        mWideGamutWindowSourceActivityRule.getActivity().offsetForContent(r);
+        return r;
+    }
+
+    @Test
+    public void testWideGamutWindowProducerCopyToRGBA8888() {
+        Window window = waitForWideGamutWindowProducerActivity();
+        assertEquals(
+                ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, window.getAttributes().getColorMode());
+
+        // Early out if the device does not support wide color gamut rendering
+        if (!window.isWideColorGamut()) {
+            return;
+        }
+
+        PixelCopyWideGamutViewProducerActivity activity =
+                mWideGamutWindowSourceActivityRule.getActivity();
+
+        Bitmap bitmap;
+        do {
+            Rect src = makeWideGamutWindowRect(0, 0, 128, 128);
+            bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888);
+            int result = mCopyHelper.request(window, src, bitmap);
+
+            assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+            assertEquals(Config.ARGB_8888, bitmap.getConfig());
+
+            assertEquals("Top left", Color.RED, bitmap.getPixel(32, 32));
+            assertEquals("Top right", Color.GREEN, bitmap.getPixel(96, 32));
+            assertEquals("Bottom left", Color.BLUE, bitmap.getPixel(32, 96));
+            assertEquals("Bottom right", Color.YELLOW, bitmap.getPixel(96, 96));
+        } while (activity.rotate());
+    }
+
+    @Test
+    public void testWideGamutWindowProducerCopyToRGBA16F() {
+        Window window = waitForWideGamutWindowProducerActivity();
+        assertEquals(
+                ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, window.getAttributes().getColorMode());
+
+        // Early out if the device does not support wide color gamut rendering
+        if (!window.isWideColorGamut()) {
+            return;
+        }
+
+        PixelCopyWideGamutViewProducerActivity activity =
+                mWideGamutWindowSourceActivityRule.getActivity();
+
+        Bitmap bitmap;
+        int i = 0;
+        do {
+            Rect src = makeWideGamutWindowRect(0, 0, 128, 128);
+            bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16);
+            int result = mCopyHelper.request(window, src, bitmap);
+
+            assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+            assertEquals(Config.RGBA_F16, bitmap.getConfig());
+
+            ByteBuffer dst = ByteBuffer.allocateDirect(bitmap.getAllocationByteCount());
+            bitmap.copyPixelsToBuffer(dst);
+            dst.rewind();
+            dst.order(ByteOrder.LITTLE_ENDIAN);
+
+            // ProPhoto RGB red in scRGB-nl
+            assertEqualsRgba16f("Top left",     bitmap, 32, 32, dst,  1.36f, -0.52f, -0.09f, 1.0f);
+            // ProPhoto RGB green in scRGB-nl
+            assertEqualsRgba16f("Top right",    bitmap, 96, 32, dst, -0.87f,  1.10f, -0.43f, 1.0f);
+            // ProPhoto RGB blue in scRGB-nl
+            assertEqualsRgba16f("Bottom left",  bitmap, 32, 96, dst, -0.59f, -0.04f,  1.07f, 1.0f);
+            // ProPhoto RGB yellow in scRGB-nl
+            assertEqualsRgba16f("Bottom right", bitmap, 96, 96, dst,  1.12f,  1.00f, -0.44f, 1.0f);
+        } while (activity.rotate());
+    }
+
+    private static void assertEqualsRgba16f(String message, Bitmap bitmap, int x, int y,
+            ByteBuffer dst, float r, float g, float b, float a) {
+        int index = y * bitmap.getRowBytes() + (x << 3);
+        short cR = dst.getShort(index);
+        short cG = dst.getShort(index + 2);
+        short cB = dst.getShort(index + 4);
+        short cA = dst.getShort(index + 6);
+
+        assertEquals(message, r, Half.toFloat(cR), 0.01);
+        assertEquals(message, g, Half.toFloat(cG), 0.01);
+        assertEquals(message, b, Half.toFloat(cB), 0.01);
+        assertEquals(message, a, Half.toFloat(cA), 0.01);
+    }
+
     private void runGcAndFinalizersSync() {
         final CountDownLatch fence = new CountDownLatch(1);
         new Object() {
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyWideGamutViewProducerActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyWideGamutViewProducerActivity.java
new file mode 100644
index 0000000..f697095
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyWideGamutViewProducerActivity.java
@@ -0,0 +1,141 @@
+/*
+ * 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 android.view.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewTreeObserver.OnDrawListener;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.fail;
+
+public class PixelCopyWideGamutViewProducerActivity extends Activity implements OnDrawListener {
+    private static final int[] ORIENTATIONS = {
+            ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
+            ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
+            ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
+            ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
+    };
+    private int mCurrentOrientation = 0;
+    private View mContent;
+    private Rect mContentBounds = new Rect();
+    private CountDownLatch mFence = new CountDownLatch(3);
+    private boolean mSupportsRotation;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Check if the device supports both of portrait and landscape orientation screens.
+        final PackageManager pm = getPackageManager();
+        mSupportsRotation = pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
+                    && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT);
+        if (mSupportsRotation) {
+            setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]);
+        }
+
+        mContent = new WideGamutBitmapView(this);
+        setContentView(mContent);
+        mContent.getViewTreeObserver().addOnDrawListener(this);
+    }
+
+    @Override
+    public void onDraw() {
+        final int requestedOrientation = ORIENTATIONS[mCurrentOrientation];
+        boolean screenPortrait =
+                requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+                || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+        boolean contentPortrait = mContent.getHeight() > mContent.getWidth();
+        if (mSupportsRotation && (screenPortrait != contentPortrait)) {
+            return;
+        }
+        mContent.post(() -> {
+            Point offset = new Point();
+            // We pass mContentBounds here just as a throwaway rect, we don't care about
+            // the visible rect just the global offset.
+            mContent.getGlobalVisibleRect(mContentBounds, offset);
+            mContentBounds.set(offset.x, offset.y,
+                    offset.x + mContent.getWidth(), offset.y + mContent.getHeight());
+            mFence.countDown();
+            if (mFence.getCount() > 0) {
+                mContent.invalidate();
+            }
+        });
+    }
+
+    public void waitForFirstDrawCompleted(int timeout, TimeUnit unit) {
+        try {
+            if (!mFence.await(timeout, unit)) {
+                fail("Timeout");
+            }
+        } catch (InterruptedException ex) {
+            fail(ex.getMessage());
+        }
+    }
+
+    public boolean rotate() {
+        if (!mSupportsRotation) {
+            // Do not rotate the screen if it is not supported.
+            return false;
+        }
+        mFence = new CountDownLatch(3);
+        runOnUiThread(() -> {
+            mCurrentOrientation = (mCurrentOrientation + 1) % ORIENTATIONS.length;
+            setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]);
+        });
+        waitForFirstDrawCompleted(3, TimeUnit.SECONDS);
+        return mCurrentOrientation != 0;
+    }
+
+    void offsetForContent(Rect inOut) {
+        inOut.offset(mContentBounds.left, mContentBounds.top);
+    }
+
+    private static final class WideGamutBitmapView extends View {
+        private final Bitmap mBitmap;
+
+        WideGamutBitmapView(Context context) {
+            super(context);
+            // We use an asset to ensure aapt will not mess with the data
+            AssetManager assets = context.getResources().getAssets();
+            try (InputStream in = assets.open("prophoto.png")) {
+                mBitmap = BitmapFactory.decodeStream(in);
+            } catch (IOException e) {
+                throw new RuntimeException("Test failed: ", e);
+            }
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
+        }
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 2550915..831aa15 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -103,7 +103,6 @@
 import com.android.compatibility.common.util.CtsMouseUtil;
 import com.android.compatibility.common.util.CtsTouchUtils;
 import com.android.compatibility.common.util.PollingCheck;
-import com.android.internal.view.menu.ContextMenuBuilder;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -1074,21 +1073,22 @@
     }
 
     @Test
-    public void testCreateContextMenu() {
-        View.OnCreateContextMenuListener listener = mock(View.OnCreateContextMenuListener.class);
-        MockView view = new MockView(mActivity);
-        ContextMenu contextMenu = new ContextMenuBuilder(mActivity);
-        view.setParent(mMockParent);
-        view.setOnCreateContextMenuListener(listener);
-        assertFalse(view.hasCalledOnCreateContextMenu());
-        assertFalse(mMockParent.hasCreateContextMenu());
-        verifyZeroInteractions(listener);
+    public void testCreateContextMenu() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            View.OnCreateContextMenuListener listener =
+                    mock(View.OnCreateContextMenuListener.class);
+            MockView view = new MockView(mActivity);
+            mActivity.setContentView(view);
+            mActivity.registerForContextMenu(view);
+            view.setOnCreateContextMenuListener(listener);
+            assertFalse(view.hasCalledOnCreateContextMenu());
+            verifyZeroInteractions(listener);
 
-        view.createContextMenu(contextMenu);
-        assertTrue(view.hasCalledOnCreateContextMenu());
-        assertTrue(mMockParent.hasCreateContextMenu());
-        verify(listener, times(1)).onCreateContextMenu(
-                eq(contextMenu), eq(view), any());
+            view.showContextMenu();
+            assertTrue(view.hasCalledOnCreateContextMenu());
+            verify(listener, times(1)).onCreateContextMenu(
+                    any(), eq(view), any());
+        });
     }
 
     @Test(expected=NullPointerException.class)
@@ -1226,32 +1226,36 @@
     }
 
     @Test
-    public void testKeyboardNavigationClusterSearch() {
-        mMockParent.setIsRootNamespace(true);
-        View v1 = new MockView(mActivity);
-        v1.setFocusableInTouchMode(true);
-        View v2 = new MockView(mActivity);
-        v2.setFocusableInTouchMode(true);
-        mMockParent.addView(v1);
-        mMockParent.addView(v2);
+    public void testKeyboardNavigationClusterSearch() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
+            decorView.removeAllViews();
+            View v1 = new MockView(mActivity);
+            v1.setFocusableInTouchMode(true);
+            View v2 = new MockView(mActivity);
+            v2.setFocusableInTouchMode(true);
+            decorView.addView(v1);
+            decorView.addView(v2);
 
-        // Searching for clusters.
-        v1.setKeyboardNavigationCluster(true);
-        v2.setKeyboardNavigationCluster(true);
-        assertEquals(v2, mMockParent.keyboardNavigationClusterSearch(v1, View.FOCUS_FORWARD));
-        assertEquals(v1, mMockParent.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
-        assertEquals(v2, mMockParent.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
-        assertEquals(v2, v1.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
-        assertEquals(mMockParent, v1.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
-        assertEquals(mMockParent, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
-        assertEquals(v1, v2.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
+            // Searching for clusters.
+            v1.setKeyboardNavigationCluster(true);
+            v2.setKeyboardNavigationCluster(true);
+            assertEquals(v2, decorView.keyboardNavigationClusterSearch(v1, View.FOCUS_FORWARD));
+            assertEquals(v1, decorView.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+            assertEquals(v2, decorView.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
+            assertEquals(v2, v1.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+            assertEquals(decorView, v1.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
+            assertEquals(decorView, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+            assertEquals(v1, v2.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
 
-        // Clusters in 3-level hierarchy.
-        ViewGroup root = new MockViewParent(mActivity);
-        root.setIsRootNamespace(true);
-        mMockParent.setIsRootNamespace(false);
-        root.addView(mMockParent);
-        assertEquals(root, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+            // Clusters in 3-level hierarchy.
+            decorView.removeAllViews();
+            LinearLayout middle = new LinearLayout(mActivity);
+            middle.addView(v1);
+            middle.addView(v2);
+            decorView.addView(middle);
+            assertEquals(decorView, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+        });
     }
 
     @Test
@@ -3661,6 +3665,67 @@
     }
 
     @Test
+    public void testScrollbarSize() {
+        final int configScrollbarSize = ViewConfiguration.get(mActivity).getScaledScrollBarSize();
+        final int customScrollbarSize = configScrollbarSize * 2;
+
+        // No explicit scrollbarSize or custom drawables, ViewConfiguration applies.
+        final MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
+        assertEquals(configScrollbarSize, view.getScrollBarSize());
+        assertEquals(configScrollbarSize, view.getVerticalScrollbarWidth());
+        assertEquals(configScrollbarSize, view.getHorizontalScrollbarHeight());
+
+        // No custom drawables, explicit scrollbarSize takes precedence.
+        final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view_2);
+        view2.setScrollBarSize(customScrollbarSize);
+        assertEquals(customScrollbarSize, view2.getScrollBarSize());
+        assertEquals(customScrollbarSize, view2.getVerticalScrollbarWidth());
+        assertEquals(customScrollbarSize, view2.getHorizontalScrollbarHeight());
+
+        // Custom drawables with no intrinsic size, ViewConfiguration applies.
+        final MockView view3 = (MockView) mActivity.findViewById(R.id.scroll_view_3);
+        assertEquals(configScrollbarSize, view3.getVerticalScrollbarWidth());
+        assertEquals(configScrollbarSize, view3.getHorizontalScrollbarHeight());
+        // Explicit scrollbarSize takes precedence.
+        view3.setScrollBarSize(customScrollbarSize);
+        assertEquals(view3.getScrollBarSize(), view3.getVerticalScrollbarWidth());
+        assertEquals(view3.getScrollBarSize(), view3.getHorizontalScrollbarHeight());
+
+        // Custom thumb drawables with intrinsic sizes define the scrollbars' dimensions.
+        final MockView view4 = (MockView) mActivity.findViewById(R.id.scroll_view_4);
+        final Resources res = mActivity.getResources();
+        final int thumbWidth = res.getDimensionPixelSize(R.dimen.scrollbar_thumb_width);
+        final int thumbHeight = res.getDimensionPixelSize(R.dimen.scrollbar_thumb_height);
+        assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
+        assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
+        // Explicit scrollbarSize has no effect.
+        view4.setScrollBarSize(customScrollbarSize);
+        assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
+        assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
+
+        // Custom thumb and track drawables with intrinsic sizes. Track size take precedence.
+        final MockView view5 = (MockView) mActivity.findViewById(R.id.scroll_view_5);
+        final int trackWidth = res.getDimensionPixelSize(R.dimen.scrollbar_track_width);
+        final int trackHeight = res.getDimensionPixelSize(R.dimen.scrollbar_track_height);
+        assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
+        assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
+        // Explicit scrollbarSize has no effect.
+        view5.setScrollBarSize(customScrollbarSize);
+        assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
+        assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
+
+        // Custom thumb and track, track with no intrinsic size, ViewConfiguration applies
+        // regardless of the thumb drawable dimensions.
+        final MockView view6 = (MockView) mActivity.findViewById(R.id.scroll_view_6);
+        assertEquals(configScrollbarSize, view6.getVerticalScrollbarWidth());
+        assertEquals(configScrollbarSize, view6.getHorizontalScrollbarHeight());
+        // Explicit scrollbarSize takes precedence.
+        view6.setScrollBarSize(customScrollbarSize);
+        assertEquals(customScrollbarSize, view6.getVerticalScrollbarWidth());
+        assertEquals(customScrollbarSize, view6.getHorizontalScrollbarHeight());
+    }
+
+    @Test
     public void testOnStartAndFinishTemporaryDetach() throws Throwable {
         final AtomicBoolean exitedDispatchStartTemporaryDetach = new AtomicBoolean(false);
         final AtomicBoolean exitedDispatchFinishTemporaryDetach = new AtomicBoolean(false);
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 6bd2fa5..dcdd4f2 100644
--- a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
+++ b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
@@ -33,12 +33,10 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewRootImpl;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
-import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -153,7 +151,7 @@
         v2.setVisibility(View.VISIBLE);
         v3.setVisibility(View.VISIBLE);
         v4.setVisibility(View.VISIBLE);
-        assertEquals(ViewRootImpl.sAlwaysAssignFocus, v1.isFocused());
+        assertEquals(true, v1.isFocused());
         assertFalse(v2.isFocused());
         assertFalse(v3.isFocused());
         assertFalse(v4.isFocused());
@@ -344,32 +342,6 @@
         return new View[]{initial, first};
     }
 
-    @Test
-    public void testNoInitialFocus() throws Throwable {
-        Assume.assumeFalse(ViewRootImpl.sAlwaysAssignFocus);
-        Activity activity = mActivityRule.getActivity();
-        View[] result = getInitialAndFirstFocus(R.layout.focus_handling_focusables);
-        assertNull(result[0]);
-        assertSame(result[1], activity.findViewById(R.id.focusable1));
-    }
-
-    @Test
-    public void testDefaultFocus() throws Throwable {
-        Assume.assumeFalse(ViewRootImpl.sAlwaysAssignFocus);
-        Activity activity = mActivityRule.getActivity();
-        View[] result = getInitialAndFirstFocus(R.layout.focus_handling_default_focus);
-        assertNull(result[0]);
-        assertSame(result[1], activity.findViewById(R.id.focusable2));
-    }
-
-    @Test
-    public void testInitialFocus() throws Throwable {
-        Assume.assumeFalse(ViewRootImpl.sAlwaysAssignFocus);
-        Activity activity = mActivityRule.getActivity();
-        View[] result = getInitialAndFirstFocus(R.layout.focus_handling_initial_focus);
-        assertSame(result[0], activity.findViewById(R.id.focusable3));
-    }
-
     @UiThreadTest
     @Test
     public void testFocusAfterDescendantsTransfer() throws Throwable {
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
index f9c86cc..71ca678 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
@@ -17,14 +17,19 @@
 package android.view.textclassifier.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.os.LocaleList;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextSelection;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -35,33 +40,82 @@
 public class TextClassificationManagerTest {
 
     private static final LocaleList LOCALES = LocaleList.forLanguageTags("en");
+    private static final int START = 1;
+    private static final int END = 3;
+    private static final String TEXT = "text";
 
-    private TextClassificationManager mTcm;
+    private TextClassificationManager mManager;
     private TextClassifier mClassifier;
 
     @Before
     public void setup() {
-        mTcm = InstrumentationRegistry.getTargetContext()
+        mManager = InstrumentationRegistry.getTargetContext()
                 .getSystemService(TextClassificationManager.class);
-        mTcm.setTextClassifier(null); // Resets the classifier.
-        mClassifier = mTcm.getTextClassifier();
+        mManager.setTextClassifier(null); // Resets the classifier.
+        mClassifier = mManager.getTextClassifier();
     }
 
     @Test
-    public void testSmartSelectionDoesNotThrowException() {
-        mClassifier.suggestSelection("text", 2, 3, LOCALES);
+    public void testSmartSelection() {
+        assertValidResult(mClassifier.suggestSelection(TEXT, START, END, LOCALES));
     }
 
     @Test
-    public void testClassifyTextDoesNotThrowException() {
-        mClassifier.classifyText("text", 2, 3, LOCALES);
+    public void testClassifyText() {
+        assertValidResult(mClassifier.classifyText(TEXT, START, END, LOCALES));
+    }
+
+    @Test
+    public void testNoOpClassifier() {
+        mManager.setTextClassifier(TextClassifier.NO_OP);
+        mClassifier = mManager.getTextClassifier();
+
+        final TextSelection selection = mClassifier.suggestSelection(TEXT, START, END, LOCALES);
+        assertValidResult(selection);
+        assertEquals(START, selection.getSelectionStartIndex());
+        assertEquals(END, selection.getSelectionEndIndex());
+        assertEquals(0, selection.getEntityCount());
+
+        final TextClassification classification =
+                mClassifier.classifyText(TEXT, START, END, LOCALES);
+        assertValidResult(classification);
+        assertNull(classification.getText());
+        assertEquals(0, classification.getEntityCount());
+        assertNull(classification.getIcon());
+        assertNull(classification.getLabel());
+        assertNull(classification.getIntent());
+        assertNull(classification.getOnClickListener());
     }
 
     @Test
     public void testSetTextClassifier() {
-        TextClassifier classifier = mock(TextClassifier.class);
-        mTcm.setTextClassifier(classifier);
-        assertEquals(classifier, mTcm.getTextClassifier());
+        final TextClassifier classifier = mock(TextClassifier.class);
+        mManager.setTextClassifier(classifier);
+        assertEquals(classifier, mManager.getTextClassifier());
+    }
+
+    private static void assertValidResult(TextSelection selection) {
+        assertNotNull(selection);
+        assertTrue(selection.getEntityCount() >= 0);
+        for (int i = 0; i < selection.getEntityCount(); i++) {
+            final String entity = selection.getEntity(i);
+            assertNotNull(entity);
+            final float confidenceScore = selection.getConfidenceScore(entity);
+            assertTrue(confidenceScore >= 0);
+            assertTrue(confidenceScore <= 1);
+        }
+    }
+
+    private static void assertValidResult(TextClassification classification) {
+        assertNotNull(classification);
+        assertTrue(classification.getEntityCount() >= 0);
+        for (int i = 0; i < classification.getEntityCount(); i++) {
+            final String entity = classification.getEntity(i);
+            assertNotNull(entity);
+            final float confidenceScore = classification.getConfidenceScore(entity);
+            assertTrue(confidenceScore >= 0);
+            assertTrue(confidenceScore <= 1);
+        }
     }
 }
 
diff --git a/tests/tests/voiceinteraction/Android.mk b/tests/tests/voiceinteraction/Android.mk
index 67cbf3d..b83f4e9 100644
--- a/tests/tests/voiceinteraction/Android.mk
+++ b/tests/tests/voiceinteraction/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsVoiceInteractionTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 
 LOCAL_SDK_VERSION := current
diff --git a/tests/tests/voiceinteraction/service/Android.mk b/tests/tests/voiceinteraction/service/Android.mk
index c274e85..0b504d8 100644
--- a/tests/tests/voiceinteraction/service/Android.mk
+++ b/tests/tests/voiceinteraction/service/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsVoiceInteractionService
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/voiceinteraction/testapp/Android.mk b/tests/tests/voiceinteraction/testapp/Android.mk
index 79e0fbd..1c37e51 100644
--- a/tests/tests/voiceinteraction/testapp/Android.mk
+++ b/tests/tests/voiceinteraction/testapp/Android.mk
@@ -30,6 +30,6 @@
 LOCAL_SDK_VERSION := current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/voicesettings/Android.mk b/tests/tests/voicesettings/Android.mk
index 926547b..cad36cb 100644
--- a/tests/tests/voicesettings/Android.mk
+++ b/tests/tests/voicesettings/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsVoiceSettingsTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/voicesettings/service/Android.mk b/tests/tests/voicesettings/service/Android.mk
index ad008a5..d53c52b 100644
--- a/tests/tests/voicesettings/service/Android.mk
+++ b/tests/tests/voicesettings/service/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_PACKAGE_NAME := CtsVoiceSettingsService
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/webkit/Android.mk b/tests/tests/webkit/Android.mk
index 43f1bba..c56f00e 100644
--- a/tests/tests/webkit/Android.mk
+++ b/tests/tests/webkit/Android.mk
@@ -34,7 +34,7 @@
 LOCAL_PACKAGE_NAME := CtsWebkitTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
diff --git a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
index 1e9f5e8..ac736cf 100644
--- a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
@@ -57,13 +57,22 @@
             + "    <script>\n"
             + "      navigator.serviceWorker.register('sw.js').then(function(reg) {\n"
             + "         " + JS_INTERFACE_NAME + ".registrationSuccess();\n"
-            + "      }).catch(function(err) { \n"
+            + "      }).catch(function(err) {\n"
             + "         console.error(err);\n"
             + "      });\n"
             + "    </script>\n"
             + "  </body>\n"
             + "</html>\n";
     private static final String SW_RAW_HTML = "fetch('fetch.html');";
+    private static final String SW_UNREGISTER_RAW_JS =
+            "navigator.serviceWorker.getRegistration().then(function(r) {"
+            + "  r.unregister().then(function(success) {"
+            + "    if (success) " + JS_INTERFACE_NAME + ".unregisterSuccess();"
+            + "    else console.error('unregister() was not successful');"
+            + "  });"
+            + "}).catch(function(err) {"
+            + "   console.error(err);"
+            + "});";
 
     private JavascriptStatusReceiver mJavascriptStatusReceiver;
     private WebViewOnUiThread mOnUiThread;
@@ -171,17 +180,34 @@
         assertEquals(2, requests.size());
         assertEquals(SW_URL, requests.get(0).getUrl().toString());
         assertEquals(FETCH_URL, requests.get(1).getUrl().toString());
+
+        // Clean-up, make sure to unregister the Service Worker.
+        mOnUiThread.evaluateJavascript(SW_UNREGISTER_RAW_JS, null);
+        Callable<Boolean> unregisterSuccess = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return mJavascriptStatusReceiver.mUnregisterSuccess;
+            }
+        };
+        PollingCheck.check("JS could not unregister Service Worker", POLLING_TIMEOUT,
+                unregisterSuccess);
     }
 
     // Object added to the page via AddJavascriptInterface() that is used by the test Javascript to
     // notify back to Java if the Service Worker registration was successful.
     public final static class JavascriptStatusReceiver {
         public volatile boolean mRegistrationSuccess = false;
+        public volatile boolean mUnregisterSuccess = false;
 
         @JavascriptInterface
         public void registrationSuccess() {
             mRegistrationSuccess = true;
         }
+
+        @JavascriptInterface
+        public void unregisterSuccess() {
+            mUnregisterSuccess = true;
+        }
     }
 }
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index d77af03..0792150 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -16,7 +16,9 @@
 
 package android.webkit.cts;
 
+import android.app.ActivityManager;
 import android.graphics.Bitmap;
+import android.os.Build;
 import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
@@ -580,6 +582,12 @@
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
+        if (Build.SUPPORTED_64_BIT_ABIS.length == 0 &&
+            getActivity().getSystemService(ActivityManager.class).isLowRamDevice()) {
+            // Renderer process crashes can only be handled when multiprocess is enabled,
+            // which is not the case for 32-bit lowram devices.
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         mOnUiThread.loadUrl("chrome://kill");
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index 653ef77..ec104d8 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -37,6 +37,6 @@
 LOCAL_PACKAGE_NAME := CtsWidgetTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/widget/AndroidTest.xml b/tests/tests/widget/AndroidTest.xml
index f84c222..2eb0b86 100644
--- a/tests/tests/widget/AndroidTest.xml
+++ b/tests/tests/widget/AndroidTest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Widget test cases">
-    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsWidgetTestCases.apk" />
diff --git a/tests/tests/widget/res/layout/relative_layout_bidi.xml b/tests/tests/widget/res/layout/relative_layout_bidi.xml
new file mode 100644
index 0000000..de4ddd7
--- /dev/null
+++ b/tests/tests/widget/res/layout/relative_layout_bidi.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" >
+
+    <RelativeLayout
+        android:id="@+id/relative_sublayout_bidi"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <TextView
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:layout_marginStart="60dp"
+            android:layout_marginEnd="20dp" />
+    </RelativeLayout>
+
+</RelativeLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
index c4a4070..a08f5b4 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -854,6 +854,22 @@
                 expectedCheckedItems, mListView.getCheckedItemPositions());
     }
 
+    @Test
+    @UiThreadTest
+    public void testCheckItemCount() throws Throwable {
+        final ArrayList<String> items = new ArrayList<>(Arrays.asList(COUNTRY_LIST));
+        final ArrayAdapter<String> adapter = new PositionArrayAdapter<>(mContext,
+                android.R.layout.simple_list_item_1, items);
+        mListView.setAdapter(adapter);
+        mListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
+        mListView.setItemChecked(0, true);
+        mListView.setItemChecked(1, true);
+        assertEquals(2, mListView.getCheckedItemCount());
+
+        mListView.setAdapter(adapter);
+        assertEquals(0, mListView.getCheckedItemCount());
+    }
+
     @MediumTest
     @Test
     public void testCheckedItemsUnderNoneChoiceMode() throws Throwable {
diff --git a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
index 7595c98..4350103 100644
--- a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
@@ -29,8 +29,8 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.database.DataSetObserver;
-import android.support.test.annotation.UiThreadTest;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
@@ -402,7 +402,20 @@
      */
     @Test
     public void testCreateFromResource() {
-        ArrayAdapter.createFromResource(mContext, R.array.string, R.layout.simple_spinner_item);
+        final ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
+                R.array.string, R.layout.simple_spinner_item);
+        final CharSequence[] staticOptions = adapter.getAutofillOptions();
+        assertEquals(3, staticOptions.length);
+        assertEquals("Test String 1", staticOptions[0]);
+        assertEquals("Test String 2", staticOptions[1]);
+        assertEquals("Test String 3", staticOptions[2]);
+
+        // Make sure values set dynamically wins.
+        adapter.setAutofillOptions("Dynamic", "am I");
+        final CharSequence[] dynamicOptions = adapter.getAutofillOptions();
+        assertEquals(2, dynamicOptions.length);
+        assertEquals("Dynamic", dynamicOptions[0]);
+        assertEquals("am I", dynamicOptions[1]);
 
         ArrayAdapter.createFromResource(mContext, R.array.string, INVALID_ID);
     }
diff --git a/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java b/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
index 42c3269..4df0c4a 100644
--- a/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
@@ -123,6 +123,23 @@
         assertFalse(baseAdapter.isEmpty());
     }
 
+    @Test
+    public void testGetAutofillOptions() {
+        MockBaseAdapter baseAdapter = new MockBaseAdapter();
+        assertNull(baseAdapter.getAutofillOptions());
+
+        baseAdapter.setAutofillOptions("single");
+        CharSequence[] single = baseAdapter.getAutofillOptions();
+        assertEquals(1, single.length);
+        assertEquals("single", single[0]);
+
+        baseAdapter.setAutofillOptions("mult1", "mult2");
+        CharSequence[] multiple = baseAdapter.getAutofillOptions();
+        assertEquals(2, multiple.length);
+        assertEquals("mult1", multiple[0]);
+        assertEquals("mult2", multiple[1]);
+    }
+
     private static class MockBaseAdapter extends BaseAdapter {
         private int mCount = 0;
 
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
index 3fb141e..9e23a2d 100644
--- a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.app.Instrumentation;
+import android.app.UiAutomation;
 import android.content.res.Configuration;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
@@ -35,6 +36,7 @@
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.NumberPicker;
 
 import com.android.compatibility.common.util.CtsTouchUtils;
@@ -51,8 +53,10 @@
     private static final String[] NUMBER_NAMES3 = {"One", "Two", "Three"};
     private static final String[] NUMBER_NAMES_ALT3 = {"Three", "Four", "Five"};
     private static final String[] NUMBER_NAMES5 = {"One", "Two", "Three", "Four", "Five"};
+    private static final long TIMEOUT_ACCESSIBILITY_EVENT = 5 * 1000;
 
     private Instrumentation mInstrumentation;
+    private UiAutomation mUiAutomation;
     private NumberPickerCtsActivity mActivity;
     private NumberPicker mNumberPicker;
 
@@ -63,6 +67,7 @@
     @Before
     public void setup() {
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mUiAutomation = mInstrumentation.getUiAutomation();
         mActivity = mActivityRule.getActivity();
         mNumberPicker = (NumberPicker) mActivity.findViewById(R.id.number_picker);
     }
@@ -261,32 +266,43 @@
                 mNumberPicker.getDisplayedValueForCurrentSelection()));
     }
 
-    @UiThreadTest
     @Test
-    public void testAccessValue() {
-        mNumberPicker.setMinValue(20);
-        mNumberPicker.setMaxValue(22);
-        mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
-
+    public void testAccessValue() throws Throwable {
         final NumberPicker.OnValueChangeListener mockValueChangeListener =
                 mock(NumberPicker.OnValueChangeListener.class);
-        mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
 
-        mNumberPicker.setValue(21);
-        assertEquals(21, mNumberPicker.getValue());
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(20);
+            mNumberPicker.setMaxValue(22);
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
 
-        mNumberPicker.setValue(20);
-        assertEquals(20, mNumberPicker.getValue());
+            mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+        });
 
-        mNumberPicker.setValue(22);
-        assertEquals(22, mNumberPicker.getValue());
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setValue(21);
+            assertEquals(21, mNumberPicker.getValue());
+        });
 
-        // Check trying to set value out of min/max range
-        mNumberPicker.setValue(10);
-        assertEquals(20, mNumberPicker.getValue());
+        mUiAutomation.executeAndWaitForEvent(() ->
+                        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(20)),
+                (AccessibilityEvent event) ->
+                        event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED,
+                TIMEOUT_ACCESSIBILITY_EVENT);
 
-        mNumberPicker.setValue(100);
-        assertEquals(22, mNumberPicker.getValue());
+        mInstrumentation.runOnMainSync(() -> {
+            assertEquals(20, mNumberPicker.getValue());
+
+            mNumberPicker.setValue(22);
+            assertEquals(22, mNumberPicker.getValue());
+
+            // Check trying to set value out of min/max range
+            mNumberPicker.setValue(10);
+            assertEquals(20, mNumberPicker.getValue());
+
+            mNumberPicker.setValue(100);
+            assertEquals(22, mNumberPicker.getValue());
+        });
 
         // Since all changes to value are via API calls, we should have no interactions /
         // callbacks on our listener.
@@ -370,11 +386,15 @@
         final int[] numberPickerLocationOnScreen = new int[2];
         mNumberPicker.getLocationOnScreen(numberPickerLocationOnScreen);
 
-        CtsTouchUtils.emulateDragGesture(mInstrumentation,
-                numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2,
-                numberPickerLocationOnScreen[1] + mNumberPicker.getHeight() - 1,
-                0,
-                - (mNumberPicker.getHeight() - 2));
+        mUiAutomation.executeAndWaitForEvent(() ->
+                        CtsTouchUtils.emulateDragGesture(mInstrumentation,
+                                numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2,
+                                numberPickerLocationOnScreen[1] + mNumberPicker.getHeight() - 1,
+                                0,
+                                -(mNumberPicker.getHeight() - 2)),
+                (AccessibilityEvent event) ->
+                        event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED,
+                TIMEOUT_ACCESSIBILITY_EVENT);
 
         // At this point we expect that the drag-up gesture has selected the value
         // that was "below" the previously selected one, and that our value change listener
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
index bebebf2..76415e8 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
@@ -359,6 +359,33 @@
         assertTrue(button.getHeight() > 0);
     }
 
+    @Test
+    public void testBidiWidth() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(R.layout.relative_layout_bidi);
+            mActivity.findViewById(R.id.relative_sublayout_bidi)
+                     .setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        final View ltrLayout = mActivity.findViewById(R.id.relative_sublayout_bidi);
+        assertNotNull(ltrLayout);
+        final int ltrWidth = ltrLayout.getWidth();
+
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(R.layout.relative_layout_bidi);
+            mActivity.findViewById(R.id.relative_sublayout_bidi)
+                     .setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        final View rtlLayout = mActivity.findViewById(R.id.relative_sublayout_bidi);
+        assertNotNull(rtlLayout);
+        final int rtlWidth = rtlLayout.getWidth();
+
+        assertEquals(ltrWidth, rtlWidth);
+    }
+
     private class MyRelativeLayout extends RelativeLayout {
         public MyRelativeLayout(Context context) {
             super(context);
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 4e71fdd..7003f51 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -3580,7 +3580,8 @@
         mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
         mInstrumentation.waitForIdleSync();
 
-        final float halfCharWidth = (float) Math.ceil(mTextView.getPaint().measureText("a") / 2f);
+        final float horizontalPosFix = (float) Math.ceil(
+                mTextView.getPaint().measureText("a") * 2f / 3f);
         final int paddingTop = mTextView.getTotalPaddingTop();
         final int paddingLeft = mTextView.getTotalPaddingLeft();
 
@@ -3594,7 +3595,7 @@
         assertEquals(firstOffset, mTextView.getOffsetForPosition(x, y));
 
         // right edge of text
-        x = mTextView.getLayout().getLineWidth(0) + paddingLeft - halfCharWidth;
+        x = mTextView.getLayout().getLineWidth(0) + paddingLeft - horizontalPosFix;
         assertEquals(lastOffset, mTextView.getOffsetForPosition(x, y));
 
         // right edge of view
@@ -3606,7 +3607,7 @@
         assertEquals(firstOffset, mTextView.getOffsetForPosition(x, y));
 
         // horizontal center of text
-        x = mTextView.getLayout().getLineWidth(0) / 2f + paddingLeft - halfCharWidth;
+        x = mTextView.getLayout().getLineWidth(0) / 2f + paddingLeft - horizontalPosFix;
         assertEquals(midOffset, mTextView.getOffsetForPosition(x, y));
     }
 
@@ -3640,7 +3641,8 @@
         final Rect lineBounds = new Rect();
         mTextView.getLayout().getLineBounds(0, lineBounds);
 
-        final float halfCharWidth = (float) Math.ceil(mTextView.getPaint().measureText("a") / 2f);
+        final float horizontalPosFix = (float) Math.ceil(
+                mTextView.getPaint().measureText("a") * 2f / 3f);
         final int paddingTop = mTextView.getTotalPaddingTop();
         final int paddingLeft = mTextView.getTotalPaddingLeft();
 
@@ -3662,7 +3664,7 @@
         assertEquals(line.length(), mTextView.getOffsetForPosition(x, y));
 
         // right edge of text at second line
-        x = mTextView.getLayout().getLineWidth(1) + paddingLeft - halfCharWidth;
+        x = mTextView.getLayout().getLineWidth(1) + paddingLeft - horizontalPosFix;
         assertEquals(line.length() + line.length() - 1, mTextView.getOffsetForPosition(x, y));
 
         // right edge of view at second line
@@ -3670,7 +3672,7 @@
         assertEquals(line.length() + line.length() - 1, mTextView.getOffsetForPosition(x, y));
 
         // horizontal center of text at second line
-        x = mTextView.getLayout().getLineWidth(1) / 2f + paddingLeft - halfCharWidth;
+        x = mTextView.getLayout().getLineWidth(1) / 2f + paddingLeft - horizontalPosFix;
         // second line mid offset should not include next line, therefore subtract one
         assertEquals(line.length() + (line.length() - 1) / 2, mTextView.getOffsetForPosition(x, y));
     }
@@ -3705,8 +3707,8 @@
         final Rect lineBounds = new Rect();
         mTextView.getLayout().getLineBounds(0, lineBounds);
 
-        final float halfCharWidth = (float) Math.ceil(
-                mTextView.getPaint().measureText("\u0635") / 2f);
+        final float horizontalPosFix = (float) Math.ceil(
+                mTextView.getPaint().measureText("\u0635") * 2f / 3f);
         final int paddingTop = mTextView.getTotalPaddingTop();
         final int paddingRight = mTextView.getTotalPaddingRight();
 
@@ -3733,12 +3735,12 @@
 
         // left edge of text at second line
         x = mTextView.getWidth() - (mTextView.getLayout().getLineWidth(1) + paddingRight
-                - halfCharWidth);
+                - horizontalPosFix);
         assertEquals(line.length() + line.length() - 1, mTextView.getOffsetForPosition(x, y));
 
         // horizontal center of text at second line
         x = mTextView.getWidth() - (mTextView.getLayout().getLineWidth(1) / 2f + paddingRight
-                - halfCharWidth);
+                - horizontalPosFix);
         // second line mid offset should not include next line, therefore subtract one
         assertEquals(line.length() + (line.length() - 1) / 2, mTextView.getOffsetForPosition(x, y));
     }
@@ -6675,7 +6677,7 @@
         // Configure layout params and auto-size both in pixels to dodge flakiness on different
         // devices.
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                500, 500);
+                200, 200);
         mActivityRule.runOnUiThread(() -> {
             autoSizeTextView.setLayoutParams(layoutParams);
             autoSizeTextView.setAutoSizeTextTypeUniformWithConfiguration(
@@ -6684,7 +6686,8 @@
         mInstrumentation.waitForIdleSync();
 
         final String initialText = "13characters ";
-        StringBuilder textToSet = new StringBuilder().append(initialText);
+        final StringBuilder textToSet = new StringBuilder().append(initialText);
+        float initialSize = 0;
 
         // As we add characters the text size shrinks.
         for (int i = 0; i < 10; i++) {
@@ -6692,29 +6695,38 @@
                     autoSizeTextView.setText(textToSet.toString()));
             mInstrumentation.waitForIdleSync();
             float expectedLargerSize = autoSizeTextView.getTextSize();
+            if (i == 0) {
+                initialSize = expectedLargerSize;
+            }
 
             textToSet.append(initialText);
             mActivityRule.runOnUiThread(() ->
                     autoSizeTextView.setText(textToSet.toString()));
             mInstrumentation.waitForIdleSync();
 
-            assertTrue(expectedLargerSize > autoSizeTextView.getTextSize());
+            assertTrue(expectedLargerSize >= autoSizeTextView.getTextSize());
         }
+        assertTrue(initialSize > autoSizeTextView.getTextSize());
 
+        initialSize = Integer.MAX_VALUE;
         // As we remove characters the text size expands.
         for (int i = 9; i >= 0; i--) {
             mActivityRule.runOnUiThread(() ->
                     autoSizeTextView.setText(textToSet.toString()));
             mInstrumentation.waitForIdleSync();
             float expectedSmallerSize = autoSizeTextView.getTextSize();
+            if (i == 9) {
+                initialSize = expectedSmallerSize;
+            }
 
             textToSet.replace((textToSet.length() - initialText.length()), textToSet.length(), "");
             mActivityRule.runOnUiThread(() ->
                     autoSizeTextView.setText(textToSet.toString()));
             mInstrumentation.waitForIdleSync();
 
-            assertTrue(autoSizeTextView.getTextSize() > expectedSmallerSize);
+            assertTrue(autoSizeTextView.getTextSize() >= expectedSmallerSize);
         }
+        assertTrue(autoSizeTextView.getTextSize() > initialSize);
     }
 
     @Test
@@ -6954,11 +6966,53 @@
     public void testAutoSizeCallers_setMaxLines() throws Throwable {
         final TextView autoSizeTextView = prepareAndRetrieveAutoSizeTestData(
                 R.id.textview_autosize_uniform, false);
-        final float initialTextSize = autoSizeTextView.getTextSize();
-        mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxLines(1));
+        // Configure layout params and auto-size both in pixels to dodge flakiness on different
+        // devices.
+        final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+                200, 200);
+        final String text = "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten";
+        mActivityRule.runOnUiThread(() -> {
+            autoSizeTextView.setLayoutParams(layoutParams);
+            autoSizeTextView.setAutoSizeTextTypeUniformWithConfiguration(
+                    1 /* autoSizeMinTextSize */,
+                    5000 /* autoSizeMaxTextSize */,
+                    1 /* autoSizeStepGranularity */,
+                    TypedValue.COMPLEX_UNIT_PX);
+            autoSizeTextView.setText(text);
+        });
         mInstrumentation.waitForIdleSync();
 
-        assertTrue(autoSizeTextView.getTextSize() < initialTextSize);
+        float initialSize = 0;
+        for (int i = 1; i < 10; i++) {
+            final int maxLines = i;
+            mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxLines(maxLines));
+            mInstrumentation.waitForIdleSync();
+            float expectedSmallerSize = autoSizeTextView.getTextSize();
+            if (i == 1) {
+                initialSize = expectedSmallerSize;
+            }
+
+            mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxLines(maxLines + 1));
+            mInstrumentation.waitForIdleSync();
+            assertTrue(expectedSmallerSize <= autoSizeTextView.getTextSize());
+        }
+        assertTrue(initialSize < autoSizeTextView.getTextSize());
+
+        initialSize = Integer.MAX_VALUE;
+        for (int i = 10; i > 1; i--) {
+            final int maxLines = i;
+            mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxLines(maxLines));
+            mInstrumentation.waitForIdleSync();
+            float expectedLargerSize = autoSizeTextView.getTextSize();
+            if (i == 10) {
+                initialSize = expectedLargerSize;
+            }
+
+            mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxLines(maxLines - 1));
+            mInstrumentation.waitForIdleSync();
+            assertTrue(expectedLargerSize >= autoSizeTextView.getTextSize());
+        }
+        assertTrue(initialSize > autoSizeTextView.getTextSize());
     }
 
     @Test
@@ -7393,7 +7447,7 @@
 
         final String someText = "This is a string";
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                500, 500);
+                200, 200);
         // Configure identically and attach to layout.
         mActivityRule.runOnUiThread(() -> {
             granularityTextView.setLayoutParams(layoutParams);
diff --git a/tests/tests/wrap/nowrap/Android.mk b/tests/tests/wrap/nowrap/Android.mk
index eb801a1..8f70c2a 100644
--- a/tests/tests/wrap/nowrap/Android.mk
+++ b/tests/tests/wrap/nowrap/Android.mk
@@ -26,7 +26,7 @@
 	android-support-test \
 	legacy-android-test
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_SDK_VERSION := current
 
 LOCAL_PACKAGE_NAME := CtsWrapNoWrapTestCases
diff --git a/tests/tests/wrap/wrap_debug/Android.mk b/tests/tests/wrap/wrap_debug/Android.mk
index e955115..7299f02 100644
--- a/tests/tests/wrap/wrap_debug/Android.mk
+++ b/tests/tests/wrap/wrap_debug/Android.mk
@@ -26,7 +26,7 @@
 	android-support-test \
 	legacy-android-test
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_SDK_VERSION := current
 
 LOCAL_PREBUILT_JNI_LIBS_arm := ../wrap.sh
diff --git a/tests/tests/wrap/wrap_nodebug/Android.mk b/tests/tests/wrap/wrap_nodebug/Android.mk
index c4fb53f..e4a8c51 100644
--- a/tests/tests/wrap/wrap_nodebug/Android.mk
+++ b/tests/tests/wrap/wrap_nodebug/Android.mk
@@ -26,7 +26,7 @@
 	android-support-test \
 	legacy-android-test
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 LOCAL_SDK_VERSION := current
 
 LOCAL_PREBUILT_JNI_LIBS_arm := ../wrap.sh
diff --git a/tests/tvprovider/Android.mk b/tests/tvprovider/Android.mk
index 8c5aa1e..4a13909 100644
--- a/tests/tvprovider/Android.mk
+++ b/tests/tvprovider/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_PACKAGE_NAME := CtsTvProviderTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 
 LOCAL_SDK_VERSION := current
diff --git a/tests/ui/Android.mk b/tests/ui/Android.mk
index ecd00f9..53ae77e 100644
--- a/tests/ui/Android.mk
+++ b/tests/ui/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_PACKAGE_NAME := CtsUiDeviceTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/video/Android.mk b/tests/video/Android.mk
index ca55138..c70cfaf 100644
--- a/tests/video/Android.mk
+++ b/tests/video/Android.mk
@@ -32,7 +32,7 @@
 LOCAL_PACKAGE_NAME := CtsVideoTestCases
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/vm/Android.mk b/tests/vm/Android.mk
index 574ad16..d28ec0f 100755
--- a/tests/vm/Android.mk
+++ b/tests/vm/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsVmTestCases
 
diff --git a/tests/vr/Android.mk b/tests/vr/Android.mk
index c35db68..74aebf1 100644
--- a/tests/vr/Android.mk
+++ b/tests/vr/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index d87ca41..2f11db9 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_PACKAGE_NAME := CtsDeviceInfo
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_CTS_DEVICE_INFO_PACKAGE)
 
diff --git a/tools/cts-device-info/src/com/android/cts/deviceinfo/SensorDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/SensorDeviceInfo.java
index 1d266f5..9d61dd8 100644
--- a/tools/cts-device-info/src/com/android/cts/deviceinfo/SensorDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/SensorDeviceInfo.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.hardware.Sensor;
+import android.hardware.SensorDirectChannel;
 import android.hardware.SensorManager;
 import android.os.Bundle;
 
@@ -25,6 +26,7 @@
 
 import java.lang.Exception;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -52,6 +54,13 @@
     private static final String IS_DYNAMIC_SENSOR = "is_dynamic_sensor";
     private static final String IS_ADDITONAL_INFO_SUPPORTED =
             "is_additional_info_supported";
+    private static final String HIGHEST_DIRECT_REPORT_RATE_LEVEL =
+            "highest_direct_report_rate_level";
+    private static final String SUPPORTED_DIRECT_CHANNEL_TYPE =
+            "supported_direct_channel_type";
+    private static final int[] CHANNEL_TYPES = new int[] {
+            SensorDirectChannel.TYPE_MEMORY_FILE,
+            SensorDirectChannel.TYPE_HARDWARE_BUFFER };
 
     @Override
     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
@@ -81,6 +90,17 @@
             store.addResult(IS_DYNAMIC_SENSOR, sensor.isDynamicSensor());
             store.addResult(IS_ADDITONAL_INFO_SUPPORTED,
                     sensor.isAdditionalInfoSupported());
+            store.addResult(HIGHEST_DIRECT_REPORT_RATE_LEVEL,
+                    sensor.getHighestDirectReportRateLevel());
+
+            List<Integer> supportedChannelType = new ArrayList<>();
+            for (int channelType : CHANNEL_TYPES) {
+                if (sensor.isDirectChannelTypeSupported(channelType)) {
+                    supportedChannelType.add(channelType);
+                }
+            }
+            store.addArrayResult(SUPPORTED_DIRECT_CHANNEL_TYPE,
+                    supportedChannelType.stream().mapToInt(i->i).toArray());
             store.endGroup();
         }
         store.endArray(); // Sensor
diff --git a/tools/cts-preconditions/Android.mk b/tools/cts-preconditions/Android.mk
index 8c36c21..76bfaa8 100644
--- a/tools/cts-preconditions/Android.mk
+++ b/tools/cts-preconditions/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 LOCAL_PACKAGE_NAME := CtsPreconditions
 
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index a78c499..4e8cae8 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -162,12 +162,6 @@
     <!-- b/62481870 -->
     <option name="compatibility:exclude-filter" value="CtsNativeMediaAAudioTestCases android.nativemedia.aaudio.AAudioOutputStreamCallbackTest#testPlayback" />
 
-    <!-- b/62844160 -->
-    <option name="compatibility:exclude-filter" value="CtsWidgetTestCases android.widget.cts.TextViewTest#testAutoSizeCallers_setText" />
-    <option name="compatibility:exclude-filter" value="CtsWidgetTestCases android.widget.cts.TextViewTest#testGetOffsetForPositionSingleLineLtr" />
-    <option name="compatibility:exclude-filter" value="CtsWidgetTestCases android.widget.cts.TextViewTest#testGetOffsetForPositionMultiLineLtr" />
-    <option name="compatibility:exclude-filter" value="CtsWidgetTestCases android.widget.cts.TextViewTest#testGetOffsetForPositionMultiLineRtl" />
-
     <!-- b/62976713 -->
     <option name="compatibility:exclude-filter" value="arm64-v8a CtsMediaBitstreamsTestCases" />
     <option name="compatibility:exclude-filter" value="x86_64 CtsMediaBitstreamsTestCases" />
@@ -176,4 +170,12 @@
     <!-- 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" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyMagMultiChannel" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelMultiMode" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyGyroMultiMode" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyMagMultiMode" />
+
 </configuration>
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index a0794aa..c7d61e4 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -68,7 +68,7 @@
 LOCAL_MODULE_PATH := $(intermediates)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
@@ -96,13 +96,13 @@
 	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
 	# generated and compile the host side junit tests
 	@echo "Write generated Main_*.java files to $(PRIVATE_INTERMEDIATES_MAIN_FILES)"
-	$(hide) java \
+	$(hide) $(JAVA) \
 	    $(if $(EXPERIMENTAL_USE_OPENJDK9),--add-exports jdk.jartool/sun.tools.jar=ALL-UNNAMED) \
 	    -cp $(PRIVATE_CLASS_PATH) util.build.BuildDalvikSuite $(PRIVATE_SRC_FOLDER) $(PRIVATE_INTERMEDIATES) \
 		$(HOST_OUT_JAVA_LIBRARIES)/cts-tf-dalvik-buildutil.jar:$(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar \
 		$(PRIVATE_INTERMEDIATES_MAIN_FILES) $(PRIVATE_INTERMEDIATES_CLASSES) $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES) $$RUN_VM_TESTS_RTO
 	@echo "Generate $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)"
-	$(hide) jar -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar \
+	$(hide) $(JAR) -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar \
 		$(addprefix -C $(PRIVATE_INTERMEDIATES_CLASSES) , dot/junit/DxUtil.class dot/junit/DxAbstractMain.class)
 	$(hide) $(DX) -JXms16M -JXmx768M --dex --output=$(PRIVATE_INTERMEDIATES_DEXCORE_JAR) \
 		$(if $(NO_OPTIMIZE_DX), --no-optimize) $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar && rm -f $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar
@@ -117,11 +117,11 @@
 	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
 	# generated and compile the host side junit tests
 	@echo "Write generated Main_*.java files to $(PRIVATE_INTERMEDIATES_MAIN_FILES)"
-	$(hide) JACK_VERSION=$(PRIVATE_JACK_VERSION) java -cp $(PRIVATE_CLASS_PATH) util.build.JackBuildDalvikSuite $(JACK) $(PRIVATE_SRC_FOLDER) $(PRIVATE_INTERMEDIATES) \
+	$(hide) JACK_VERSION=$(PRIVATE_JACK_VERSION) $(JAVA) -cp $(PRIVATE_CLASS_PATH) util.build.JackBuildDalvikSuite $(JACK) $(PRIVATE_SRC_FOLDER) $(PRIVATE_INTERMEDIATES) \
 		$(PRIVATE_DALVIK_SUITE_CLASSPATH) \
 		$(PRIVATE_INTERMEDIATES_MAIN_FILES) $(PRIVATE_INTERMEDIATES_CLASSES) $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES) $$RUN_VM_TESTS_RTO
 	@echo "Generate $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)"
-	$(hide) jar -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)-class.jar \
+	$(hide) $(JAR) -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)-class.jar \
 		$(addprefix -C $(PRIVATE_INTERMEDIATES_CLASSES) , dot/junit/DxUtil.class dot/junit/DxAbstractMain.class)
 	$(hide) $(call call-jack) --import $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)-class.jar --output-jack $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jack
 	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).tmp
diff --git a/tools/vm-tests-tf/src/util/build/JarBuildStep.java b/tools/vm-tests-tf/src/util/build/JarBuildStep.java
index 776e9059..7fbe2d5 100644
--- a/tools/vm-tests-tf/src/util/build/JarBuildStep.java
+++ b/tools/vm-tests-tf/src/util/build/JarBuildStep.java
@@ -16,28 +16,36 @@
 
 package util.build;
 
-import sun.tools.jar.Main;
-
+import java.io.BufferedInputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
 
-
+/**
+ * JarBuildStep takes a single input file and embeds it into a (new) jar file as a single entry.
+ */
 public class JarBuildStep extends BuildStep {
 
-    String destFileName;
+    String outputJarEntryName;
     private final boolean deleteInputFileAfterBuild;
 
-    public JarBuildStep(BuildFile inputFile, String destFileName,
-            BuildFile outputFile, boolean deleteInputFileAfterBuild) {
-        super(inputFile, outputFile);
-        this.destFileName = destFileName;
+    public JarBuildStep(BuildFile inputFile, String outputJarEntryName,
+            BuildFile outputJarFile, boolean deleteInputFileAfterBuild) {
+        super(inputFile, outputJarFile);
+        this.outputJarEntryName = outputJarEntryName;
         this.deleteInputFileAfterBuild = deleteInputFileAfterBuild;
     }
 
     @Override
     boolean build() {
         if (super.build()) {
-            File tempFile = new File(inputFile.folder, destFileName);
+            File tempFile = new File(inputFile.folder, outputJarEntryName);
             try {
                 if (!inputFile.fileName.equals(tempFile)) {
                     copyFile(inputFile.fileName, tempFile);
@@ -56,25 +64,53 @@
                         + outDir.getAbsolutePath());
                 return false;
             }
-            String[] arguments = new String[] {
-                    "-cMf", outputFile.fileName.getAbsolutePath(), "-C",
-                    inputFile.folder.getAbsolutePath(), destFileName};
-            Main main = new Main(System.out, System.err, "jar");
-            boolean success = main.run(arguments);
 
-            if (success) {
-                if (tempFile != null) {
-                    tempFile.delete();
-                }
-                if (deleteInputFileAfterBuild) {
-                    inputFile.fileName.delete();
-                }
-            } else {
-                System.err.println("exception in JarBuildStep while calling jar with args:" +
-                        " \"-cMf\", "+outputFile.fileName.getAbsolutePath()+", \"-C\"," + 
-                        inputFile.folder.getAbsolutePath()+", "+ destFileName);
+            // Find the input. We'll need to look into the input folder, but check with the
+            // (relative) destination filename (this is effectively removing the inputFile folder
+            // from the entry path in the jar file).
+            Path absoluteInputPath = Paths.get(inputFile.folder.getAbsolutePath())
+                    .resolve(outputJarEntryName);
+            File absoluteInputFile = absoluteInputPath.toFile();
+            if (!absoluteInputFile.exists()) {
+                // Something went wrong.
+                throw new IllegalArgumentException(absoluteInputFile.getAbsolutePath());
             }
-            return success;
+
+            // Use a JarOutputStream to create the output jar file.
+            File jarOutFile = outputFile.fileName;
+            try (JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(jarOutFile))) {
+                // Create the JAR entry for the file. Use destFileName, and copy the timestamp
+                // from the input.
+                JarEntry entry = new JarEntry(outputJarEntryName);
+                entry.setTime(absoluteInputFile.lastModified());
+
+                // Push the entry. The stream will then be ready to accept content.
+                jarOut.putNextEntry(entry);
+
+                // Copy absoluteInputFile into the jar file.
+                Files.copy(absoluteInputPath, jarOut);
+
+                // Finish the entry.
+                jarOut.closeEntry();
+
+                // (Implicitly close the stream, finishing the jar file.)
+            } catch (Exception e) {
+                System.err.println("exception in JarBuildStep for " +
+                        outputFile.fileName.getAbsolutePath() + ", " + outputJarEntryName);
+                e.printStackTrace(System.err);
+                jarOutFile.delete();
+                return false;
+            }
+
+            // Clean up.
+            if (tempFile != null) {
+                tempFile.delete();
+            }
+            if (deleteInputFileAfterBuild) {
+                inputFile.fileName.delete();
+            }
+
+            return true;
         }
         return false;
     }
@@ -82,7 +118,7 @@
     @Override
     public int hashCode() {
         return inputFile.hashCode() ^ outputFile.hashCode()
-                ^ destFileName.hashCode();
+                ^ outputJarEntryName.hashCode();
     }
 
     @Override
@@ -91,7 +127,7 @@
             JarBuildStep other = (JarBuildStep) obj;
             return inputFile.equals(other.inputFile)
                     && outputFile.equals(other.outputFile)
-                    && destFileName.equals(other.destFileName);
+                    && outputJarEntryName.equals(other.outputJarEntryName);
 
         }
         return false;
diff --git a/tools/vm-tests-tf/targetprep/Android.mk b/tools/vm-tests-tf/targetprep/Android.mk
index b87b08a..32300b2 100644
--- a/tools/vm-tests-tf/targetprep/Android.mk
+++ b/tools/vm-tests-tf/targetprep/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MODULE := compatibility-host-vm-targetprep
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_HOST_JAVA_LIBRARY)